不同翻译单元中模板类的静态变量的显式实例化

时间:2017-12-06 09:25:13

标签: c++ templates static-variables

我正在使用包含静态变量的模板类。代码结构如下。

Header.h

template<class T> class Foo
{
public:
    static int count;
    Foo() {
        count++;
    }
    void printCount() {
        cout << count << endl;
    }
};
template<class T> int Foo<T>::count;

Source.cpp

#include "Header.h"
template<> int Foo<int>::count = 5;

的main.cpp

#include <iostream>
using namespace std;
#include "Header.h"
int main()
{
    Foo<int> obj1;
    Foo<int> obj2;
    obj1.printCount();
    obj2.printCount();
    return 0;
}

xcode8.3.3上的输出是:

 7
 7

而Visual Studio 2015上的输出是:

2
2

即。特定实例化会覆盖xcode8.3.3中的泛型实例化,但不会覆盖Visual Studio 2015中的泛型实例化。 有人可以解释这种行为差异吗? 提前谢谢。

3 个答案:

答案 0 :(得分:2)

虽然您的代码包含约束违规,但实际上并不太难以使其形成良好并且维护静态初始化的位置。对于C ++标准,请参阅[temp.expl.spec]/13

  

模板或静态数据成员的显式特化   静态数据成员模板的显式特化是一个   如果声明包含初始化程序,则定义;否则,它   是宣言。 [注意:静态数据成员的定义   需要默认初始化的模板必须使用a   支撑-INIT-列表:

template<> X Q<int>::x;                         // declaration
template<> X Q<int>::x ();                      // error: declares a function
template<> X Q<int>::x { };                     // definition
     

- 结束说明]

以上暗示仅添加此行

template<> int Foo<int>::count; // declaration

Header.h 的底部,足以让所有翻译单位知道Foo<int>::count存在于某处“。一个真正的定义可能保留在 Source.cpp

答案 1 :(得分:1)

您的计划无效:

  

[temp.expl.spec#6] 如果模板,成员模板或类模板的成员是显式专用的,则应在首次使用该特化之前声明该特化,这将导致隐式实例化在发生此类使用的每个翻译单元中进行;无需诊断。

换句话说,翻译单位应该就模板名称的含义达成一致。

下一个标准段落简洁地继续:

  

[...基本上,任何模板无论如何...] 的显式专业化声明的放置,可以根据显式专业化声明的相对位置来影响程序是否格式正确以及在上文和下文中指定的翻译单元中的实例化点。   写专业时,要注意它的位置; 或者使其编译将是一个试图点燃其自焚的试验

答案 2 :(得分:0)

gcc抱怨双重实例:

/tmp/ccUEOg7s.o:(.bss._ZN3FooIiE5countE[_ZN3FooIiE5countE]+0x0): multiple definition of `Foo<int>::count'
/tmp/ccG7CO9C.o:(.data+0x0): first defined here

因此有两个实例和一个无法看到这个的链接器,任何结果都可能是效果。

这里只是没有变量的两个实例,如果它是模板化实例则是独立的。你必须删除其中一个。

如果使用C ++ 17,则可以在标题中包含var inline。