2015-04-27 75 views
0

考虑下面的代码:模板类的静态变量的初始化,C++

//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. 当模板类的静态变量被初始化/实例化?
+0

1)类模板成员只在需要的时候被实例化。 2)这是一个棘手的问题。 –

+0

[模板静态变量](http://stackoverflow.com/questions/1553854/template-static-variable) – Quentin

+0

可能的重复总之,**永远**实例化头文件中的静态,这几乎每次都会造成麻烦。每次包含头文件时,静态都会被实例化。 – bkausbk

回答

2

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

至于instatiation的静态成员的点:

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

所以instatiation的点应该是ie。如果在main()中第一次使用类型,则在main()之后。

+0

所以当C++标准坚持所有的静态数据都应该在main不打扰之前初始化这个case的时候,我是否正确? –

+0

模板类的静态成员的构造函数肯定会在main执行之前执行。当代码构造以需要其定义的方式参照模板专业化时,将创建POI(实例化点)。 – marcinj

0

作为名称提示的模板是将用于不同参数多次的代码片段。对于模板,编译器将确保它们的方法和静态字体定义是否仅链接在一起。因此,如果您使用其默认值创建静态字段,则编译器有义务提供单个内存单元(对于相同的模板参数集),即使模板类标题包含多次。不幸的是,非模板类你需要自己管理。

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

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

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

欲了解更多信息请参考这个答案:https://stackoverflow.com/a/607335/1280316

+0

这不仅是好的做法,它还是一项要求或ODR。除非您的头文件不包含在几个TU中。 – Quentin

0

类(可能是模板或没有)可以(也应该)在任何编译单元被宣布referes它。

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

但是,当你声明一个模板,没有真正创建,直到你实例化它。由于你永远不会实例化模板,静态字段永远不会被定义,并且你不会有错误。

如果您在source1.cpp有两个不同的实例(比如A<B>)和main.cpp(比如说A<C>)都仍然会罚款:你会得到A<B>::x的来源1,自A<B>主=>两个不同的变量A<C>::xA<C>属于不同类别。

在不同的编译单元中实例化相同的类的情况比较棘手。它应该会产生一个错误,但如果这样做了,你很难在模板中声明特殊的字段。所以它被编译器处理为一个特殊情况,因为它在这个other answer中解释为不产生错误。