C++:如何使<T>模板化类的每个 T 的所有实例的 std::vector 静态?

C++: How to make std::vector<T> static for all instances of every T of a templated class?

本文关键字:实例 静态 std vector lt 何使 gt C++      更新时间:2023-10-16

我有点不确定这个问题的标题是否可以阅读,但我不知道该如何提出。

所以我有一堂课,我们称其为myclass称为:

template <class T>
class MyClass
{
public:
  ...
  std::vector<T> vecData;
  ...
  void LoadData() {/* Loads data from database into vecData collection */}
}

有点简化,代码用作:

MyClass<Cat> catInstance1;
catInstance1.LoadData();
....
MyClass<Cat> catInstance2;
catInstance2.LoadData();
...
MyClass<Dog> dogInstance1;
dogInstance1.LoadData();
...
MyClass<Dog> dogInstance2;
dogInstance2.LoadData();
...

但是,现在我希望Vecdata集合变得静态,因为该vecdata充满了对象,并且目前是针对每个实例(甚至相同的模板类型(完成的,而实际上,如果我是完美的,如果我是完美的每个模板T型只需加载一次数据。这意味着Catinstance1在调用LoadData((时将加载数据库中的数据,但是当Catinstance2调用相同功能时,它应该能够使用Catinstance1中已加载的数据。然后,同样适用于doginstance1和doginstance2。

因此,我希望Collection Vecdata在类型的每个模板类型中静态(在此示例中(实例化(CAT或DOG(。一个人如何在C 中进行?我最近开始在C 中创建自己的模板类,因此我可以在此特定情况下有所帮助。

谢谢!

编辑:根据JAROD42的评论修复了上面的代码

您只需要将成员声明为静态即可。对于模板的每个参数化,它将存在一个单独的实例。

有关更多详细信息,请参见CAN模板类在C 中具有静态成员。

您可以这样做:

class animal {
   ...
}
class cat : public animal{
  ...
}
class dog : public animal {
   ...
}
class Base {
protected:
  static std::vector<animal*> vectData;
}
std::vector<animal*> Base::vectData;
template<clas T>
class MyClass : public Base {
  void LoadData();
}

感谢大家的意见,我想我设法自己解决了!这是必须做的。

我有这个课:

template <class T>
class MyClass
{
public:
  ...
  std::vector<T> vecData;
  ...
  void LoadData() {/* Loads data from database into vecData collection */}
};

问题是我需要提供一个仍在标题文件中的静态vecdata Collection 的定义,但在myClass {}范围之外之类

简单下面的代码下方我添加了:

template <typename T>
std::vector<T> MyClass<T>::vecData = {};

这是编译的,并给了我我想要的结果;MyClass与之实例化的每个模板类型的静态集合。太好了!

考虑模板中静态成员的行为

在模板类中,为每个实例化完全推导的模板实例化静态成员,即它们都共享数据的单个实例。

因此,声明向量静态就足够了。

但要注意

...即使共享数据,所有loaddata(( - 调用将重新加载或附加新数据!

请参阅下面的广泛示例!

#include <iostream>
#include <vector> 
#include <atomic>
#include <mutex>
template <typename T>
// Simple creator class providing us data
class Creator {    
    public:
        static T Create() {
            return T();
        }
};
template <>
// Simple creator class providing us data for INTEGER, just counting up from 0 on each call.
class Creator<int> {
        static int mCounter;
    public:
        static int Create() {
            return mCounter++;
        }
};
// Don't forget to initialize.
int Creator<int>::mCounter = 0;
template <typename T>
// Loader class encapsulating thread-synchronization, "already-loaded"-handling and effective data loading mechanisms...
// Here: Using the Creator<T>
class Loader {
    public:
        Loader()
            : mLoaded(false),
              mData() {
        }
        bool LoadData() {
            // Deactivate check, to allow confirming duplicate addition of data from two equally-typed containers! EXAMPLE ONLY
            // Uncomment, to have the "load only once" functionality.
            // if(mLoaded.load())
            //      return true;
            std::lock_guard<std::mutex> guard(mLoadMutex);
            bool loaded = LoadDataImpl();
            if(loaded)
                mLoaded.store(loaded);
            return loaded;
        }
        const std::vector<T>& ConstData() const { return mData; }
    private:
        bool LoadDataImpl() {
            // Actual data loading. Return true on success. False otherwise.   
            try {
                // Code...
                for(int i=0; i<10; ++i) {
                    mData.push_back(Creator<T>::Create());
                }
                return true;
            } catch(...) { // Actually don't use the ... but specific types.
                return false;
            }
        }
        std::mutex        mLoadMutex;
        std::atomic<bool> mLoaded;
        std::vector<T>    mData;
};
template <typename T> 
// The actual container, using the STATIC loader.
// The Loader<T>-static instance is shared among all Container<T>'s!
class Container {
    static Loader<T> mLoader;
    public:
        bool LoadData() { return mLoader.LoadData(); }
        const std::vector<T>& Data() const { return mLoader.ConstData(); }
};
// Don't forget to initialize...
template <typename T>
Loader<T> Container<T>::mLoader = {};
// Example struct
struct Whatever {
    int whateverValue;    
};
int main() {
    Container<int>      intContainer;
    Container<int>      intContainer2;
    Container<bool>     boolContainer;
    Container<Whatever> whateverContainer;
    // Load data 0..10 into buffer
    if(!intContainer.LoadData()) {
        std::cout << "Cannot load data of container 1.n";
    } else {
        std::cout << "Got C1 data.n";
    }
    // Load data 11..19 into buffer, IF we have the above check for mLoaded commented.
    // Otherwise, nothing will happen here!
    if(!intContainer2.LoadData()) {
        std::cout << "Cannot load data of container 2.n";
    } else {
        std::cout << "Got C2 data.n";
    }
    // 
    // If we commented the mLoaded-precondition, we will get a print of 0..19 in the console.
    // Otherwise 0..9
    //
    for(const int& v : intContainer2.Data()) {
        std::cout << v << "n";
    }
    std::cout << std::endl;
}

我创建了一个小演示,该演示:

  • 声明一个容器
  • 使用加载程序(在所有容器之间共享(,因为它是静态的。
  • 加载程序将创建者用作虚拟databackend,在每个呼叫中计数0 int-types

这里重要的部分是,加载程序为多线程访问和原子" MLOAD"提供锁定,该锁定器是否已事先检查数据。

由于附加的数据加载逻辑会使容器本身笨拙,因此我将其封装在装载机中,并具有漂亮的单线静态装载机MLOADER。

只需阅读代码和其中的评论即可显得!