C++定义静态成员的正确方法

C++定义静态成员的正确方法,c++,C++,我试图在普通成员函数中使用静态成员。但是编译器报告了一些错误。请看一下这个代码 #include <memory> template<typename T> class MyClass { private: static std::allocator<T> alloc; T *p; public: void assign(T e) { p = alloc.allocate(1); alloc.construct(p, e);

我试图在普通成员函数中使用静态成员。但是编译器报告了一些错误。请看一下这个代码

#include <memory>

template<typename T>
class MyClass {
private:
  static std::allocator<T> alloc;
  T *p;
public:
  void assign(T e) {
    p = alloc.allocate(1);
    alloc.construct(p, e);
  }
};
我就是这样使用它的:

#include 'myclass.h'

int main() {
  MyClass<int> cls;
  cls.assign(4);

};
编译器会给出以下错误:

/Users/liuziqi/CLionProjects/cpplearning/src/tt.h:17:9: warning: instantiation of variable 'MyClass<int>::alloc' required here, but no definition is available [-Wundefined-var-template]
    p = alloc.allocate(1);
        ^
/Users/liuziqi/CLionProjects/cpplearning/src/main.cpp:49:7: note: in instantiation of member function 'MyClass<int>::assign' requested here
  cls.assign(4);
      ^
/Users/liuziqi/CLionProjects/cpplearning/src/tt.h:13:28: note: forward declaration of template entity is here
  static std::allocator<T> alloc;
                           ^
/Users/liuziqi/CLionProjects/cpplearning/src/tt.h:17:9: note: add an explicit instantiation declaration to suppress this warning if 'MyClass<int>::alloc' is explicitly instantiated in another translation unit
    p = alloc.allocate(1);
我不知道哪个部分是错的……我已经定义了静态成员和任何成员函数都应该能够使用它。此错误是否与模板相关?我刚刚学习了模板,不确定是否正确使用了它

除了回答“如何修复”这个问题之外,我还将尝试描述警告所指的内容,这个问题以前肯定已经回答过很多次了

因为MyClass是一个模板,编译器希望模板类的所有代码都可以在同一个文件MyClass.h中使用。由于您只在myclass.h中声明而没有定义alloc,因此编译器假定您犯了错误。它不是绝对需要存在的,因此是警告而不是错误,如果在其他地方定义变量,可以禁用警告,但几乎可以肯定这只是一个错误

如果您使用的是c++17,处理此问题的最简单方法是将静态成员声明为内联,因此它将在此处定义:

  static inline std::allocator<T> alloc;

直播:

我对这里的“声明”和“定义”有点困惑。我认为我在类模板中对alloc的声明已经是一个“定义”,因为这是我通常定义类成员的方式。为什么还需要在外部定义它?它看起来和我在模板中的“声明”一样……这里有什么不同。这是模板的问题吗?换句话说,如果我们不是在编写模板,而是在这里编写一个类,那么类内部的定义应该是足够的静态变量只在每个类中定义一次,而不是在每个对象中定义一次。在C++17之前,这需要类定义之外的静态成员定义。如果您熟悉的话,这与extern在非类环境中的工作方式非常相似。如果不是在模板的情况下,在另一个文件中定义一个.cpp文件是很正常的,但是由于需要为类的每个实例化定义静态变量,MyClass需要一个,MyClass需要一个不同的,等等。。。然后,该定义将出现在.h文件中,这样实例化的调用方就可以生成代码,为正在使用的模板类的确切实例化类型创建静态成员。
template<typename T>
std::allocator<T> MyClass<T>::alloc;