模板类的静态变量初始化,c ++

时间:2015-04-27 07:24:03

标签: 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(){}

在这种情况下,代码编译完美而没有错误,但是如果我从类

中删除模板限定符
class A
{
    static int x;
};

int A::x = 0;
  1. 在这种情况下,编译器错误地使用x的多个定义。任何人都可以解释这种行为吗?
  2. 当模板类的静态变量被初始化/实例化时?

4 个答案:

答案 0 :(得分:2)

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

至于静态成员的实例:

  

14.6.4.1实例化点[temp.point]   1用于函数模板特化,成员函数模板特化或特化   如果专门化是隐式实例化的,则成员函数或类模板的静态数据成员   因为它是从另一个模板特化和引用它的上下文中引用的   取决于模板参数,专业化的实例化点是   封闭专业化的实例化。否则,这种专业化的实例化点   紧跟在引用专业化的命名空间范围声明或定义之后。

这样的实例应该是ie。如果你在main()中第一次使用你的类型,就在main()之后。

答案 1 :(得分:0)

顾名思义的模板是将为不同参数多次使用的代码片段。对于模板,编译器应确保其方法和静态fiels定义是否仅链接。因此,如果使用其默认值创建静态字段,则编译器必须提供单个内存单元(对于相同的模板参数集),即使模板类标头包含多次。您需要自己管理不熟悉的非模板类。

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

答案 2 :(得分:0)

  1. 必须在cpp文件中实例化/初始化静态成员,而不是在头文件中。静态成员是类的属性而不是对象的属性,因此如果在更多cpp文件中包含头文件,则看起来您正在初始化它多次。

  2. 回答这个问题比较复杂。模板不是一个类。它是按需实例化的。这意味着每个不同的模板使用都是一个独立的“模板实例”。例如,如果您使用A<int>A<float>,那么您将拥有2个不同的类,因此您需要初始化A<int>::xA<float>::x

  3. 有关详细信息,请参阅此答案:https://stackoverflow.com/a/607335/1280316

答案 3 :(得分:0)

一个类(无论是模板还是非模板)可以(并且应该)在任何引用它的编译单元中声明。

静态字段初始化确实定义了一个变量,因此它应该只存在于一个编译单元中 - &gt;这就是为什么在课程A不是模板时出现错误的原因。

但是当你声明一个模板时,实际上并没有创建任何东西,直到你实例化它。由于您从未实例化模板,因此永远不会定义静态字段,也不会出现错误。

如果您在source1.cpp(例如A<B>)和main.cpp(比如说​​A<C>)中有两个不同的实例化,那么一切都会好的:您会得到{{1} } in source1和A<B>::x in main =&gt;自A<C>::xA<B>以来的两个不同变量是不同的类。

在不同的编译单元中实例化相同类的情况比较棘手。它应该生成错误,但如果确实如此,则很难在模板中声明特殊字段。因此,编译器会将其作为特殊情况进行处理,因为在此other answer中对此进行了解释,因此不会产生任何错误。

相关问题