C++ 模板类';s静态变量初始化,c++;

C++ 模板类';s静态变量初始化,c++;,c++,templates,static,instantiation,linkage,C++,Templates,Static,Instantiation,Linkage,考虑以下代码: //header.h template<class T> class A { static int x; }; template<class T> int A<T>::x = 0; //source1.cpp #include "header.h" void f(){} // dummy function //main.cpp #include "header.h" int main(){} 在这种情况下,编译器错误地使用了x

考虑以下代码:

//header.h
template<class T>
class A
{
    static int x;
};

template<class T>
int A<T>::x = 0;

//source1.cpp
#include "header.h"
void f(){} // dummy function


//main.cpp
#include "header.h"
int main(){}
  • 在这种情况下,编译器错误地使用了x的多个定义。有人能解释这种行为吗
  • 当模板类的静态变量被初始化/实例化时
    顾名思义,模板是用于不同参数的代码片段。对于模板,编译器要确保它们的方法和静态场定义是否仅链接到它们。因此,如果使用默认值创建静态字段,编译器必须提供单个内存单元(用于相同的模板参数集),即使多次包含模板类标头。不幸的是,非模板类需要自己管理

    至于第二个问题,我相信标准没有说明何时需要初始化静态字段,每个编译器都可以以自己的方式实现它

  • 有必要实例化/初始化cpp文件中而不是标头中的静态成员。静态成员是类的属性而不是对象的属性,因此,如果在更多cpp文件中包含头文件,则看起来您将对其进行更多次初始化

  • 这个问题的答案更为复杂。模板不是一个类。它是按需实例化的。这意味着模板的每种不同用法都是一个独立的“模板实例”。例如,如果使用
    A
    A
    ,则将有两个不同的类,因此需要初始化
    A::x
    A::x

  • 有关更多信息,请参见此答案:

    类(无论是否为模板)可以(也应该)在引用它的任何编译单元中声明

    静态字段初始化确实定义了一个变量,因此它应该只存在于一个编译单元->这就是当class
    A
    不是模板时出错的原因

    但是,当您声明模板时,在您实例化它之前,不会真正创建任何内容。由于从未实例化模板,因此从未定义静态字段,因此不会出现错误

    如果在
    source1.cpp
    (比如
    A
    )和
    main.cpp
    (比如
    A
    )中有两个不同的实例化,那么一切都会很好:在source1中可以得到
    A::x
    ,在main=>中得到
    A::x
    两个不同的变量,因为
    A
    A
    是不同的类


    在不同的编译单元中实例化同一个类的情况更为棘手。它应该会生成一个错误,但如果它生成了,您就很难在模板中声明特殊字段。因此,编译器会将其作为一个特殊情况进行处理,正如本文所述,以确保不会生成错误。

    编译器将自行删除重复的模板实例化。若您将模板类转换为常规类,那个么您的职责就是确保静态变量只存在一个定义(否则将出现链接器错误)。还请记住,不同类型的模板安装之间不会共享静态数据成员。使用c++11,您可以使用外部模板自行控制安装:

    关于静态构件的安装点:

    14.6.4.1实例化点[温度点] 1用于函数模板专用化、成员函数模板专用化或 成员函数或类模板的静态数据成员,如果专门化是隐式实例化的 因为它是从另一个模板专门化和引用它的上下文中引用的 根据模板参数,专门化的实例化点是 封闭专门化的实例化。否则,这种专门化的实例化点 紧接着引用专门化的命名空间范围声明或定义。


    因此,如果您第一次在main()内使用您的类型,安装点应该在main()之后。

    1)类模板成员仅在需要时实例化。2) 这是一个棘手的问题。简言之,可能重复的,永远不要在头文件中实例化静态,这几乎每次都会带来麻烦。每次包含头文件时,静态都会被实例化。实际上,当您的类是模板时,编译器会处理多重定义。我的问题是,在没有使用这个类的情况下是否初始化和实例化了这个静态?这不仅是一个好的实践,还是一个需求或ODR。除非您的头没有包含在几个TU中。所以当C++标准坚持所有静态数据都应该在main之前初始化,不打扰这个情况,我是正确的吗?模板类的静态成员的构造函数肯定会在主执行之前执行。POI(安装点)是在代码构造以需要其定义的方式引用模板专门化时创建的。
    class A
    {
        static int x;
    };
    
    int A::x = 0;