8

当您有一个包含静态成员的(非模板化)类时,例如:

class Foo
{
   public:

   static int x;
};

然后Foo::x必须在一个且只有一个翻译单元中定义,否则编译器会报错多个定义。所以somefile.cpp你必须定义它:

int Foo::x = 10;

这样,任何访问Foo::x的翻译单元都在访问相同的内存地址。

但是如果Foo是类模板呢?

template <class T>
class Foo
{
   public:

   static int x;
};

现在,Foo<T>::x可以在头文件中定义,方法是:

template <class T>
int Foo<T>::x = 10;

那么,如果类模板Foo在 中定义foo.hpptranslation_unit1.cpp并且translation_unit2.cpp两者都包含,那么对于模板类 Foo 的某些实例化(例如)foo.hpp的内存地址是否会因每个翻译单元而不同?Foo<T>::xFoo<int>::x

4

3 回答 3

3

这很好,在这种情况下,在头文件中定义它,编译器将确保只有一个实例,如果我们看到草案 C++ 标准部分3.2 一个定义规则6段说(强调我的):

类类型(第 9 条)、枚举类型(7.2)、带外部链接的内联函数(7.1.2)、类模板(第 14 条)、非静态函数模板(14.5.6)可以有多个定义,类模板的静态数据成员 (14.5.1.3) , 成员函数

然后我们可以转到14.5.1.3 类模板的静态数据成员部分,第1段说:

静态数据成员的定义可以在包含静态成员的类模板定义的命名空间范围内提供。

并提供以下示例:

template<class T> class X {
  static T s;
};
template<class T> T X<T>::s = 0;
于 2013-10-14T18:47:39.977 回答
2

C++ 11 标准中的 14.4 完美地回答了您的问题:

模板名称具有链接 (3.5)。非成员函数模板可以有内部链接;任何其他模板名称应具有外部链接...

因此,类模板将始终具有外部链接,其静态数据成员(无论是否为 const)也是如此。因此,Foo<int>::x无论该表达式出现在哪个翻译单元中,都将始终引用内存中的同一实体。链接器使这种情况发生。

于 2014-06-30T17:12:13.530 回答
1

[basic.def.odr]/6 在某些情况下明确允许“类模板的静态数据成员”(以及其他例外)的多个定义。

然后它继续为这样一个实体D

如果 的定义D满足所有这些要求,那么程序的行为就好像有一个 的定义D。如果 的定义D不满足这些要求,则行为未定义。

因此,在一个 TU 中实例化的模板的静态数据成员的地址比较等于在另一个 TU 中实例化的相同静态数据成员的地址。


完整的引用,上面提到的段落由我强调:

类类型、枚举类型、具有外部链接的内联函数、类模板、非静态函数模板、类模板的静态数据成员、类模板的成员函数或模板特化可以有多个定义如果每个定义出现在不同的翻译单元中,并且定义满足以下要求,则某些模板参数未在程序中指定。给定这样一个D在多个翻译单元中定义的实体,那么

  • 的每个定义D应由相同的标记序列组成;和
  • 在 的每个定义中D,根据 3.4 查找的对应名称应指在 的定义中定义的实体D,或应指同一实体,经过重载解析和部分模板特化匹配后,除了名称可以指const如果对象在 的所有定义中都具有相同的文字类型,则指向具有内部链接或没有链接的对象D,并且使用常量表达式初始化对象,并且使用对象的值(但不是地址),并且对象具有的所有定义中的相同值D;和
  • 在 的每个定义中D,对应的实体应具有相同的语言链接;和
  • 在 的每个定义中D,所指的重载运算符、对转换函数、构造函数、运算符新函数和运算符删除函数的隐式调用,应指同一函数,或在定义中定义的函数D;和
  • 在 的每个定义中D,(隐式或显式)函数调用使用的默认参数被视为其标记序列存在于 的定义中D;也就是说,默认参数受上述三个要求的约束(并且,如果默认参数具有带有默认参数的子表达式,则此要求递归适用)。
  • ifD是一个具有隐式声明构造函数的类,就好像构造函数是在使用 odr 的每个翻译单元中隐式定义的,并且每个翻译单元中的隐式定义应为基类或类调用相同的构造函数的班级成员D

如果D是一个模板并且在多个翻译单元中定义,那么前面的要求既适用于模板定义中使用的模板封闭范围的名称,也适用于实例化点的依赖名称。如果 的定义D满足所有这些要求,那么程序的行为就好像有一个 的定义D如果 的定义D不满足这些要求,则行为未定义。

于 2013-10-14T18:46:32.180 回答