没有定义初始化器的静态const成员的定义?

时间:2011-02-17 17:57:47

标签: c++ templates c++11 instantiation

假设:

template<class T>
struct S {
  static int const N = 1;
};

extern template class S<int>;

template<class T>
int f( T n ) {
  return n + S<T>::N; // line 10
}

int main() {
  return f(1);        // line 14
}

//template class S<int>; // intentionally commented out to trigger error

我明白了:

foo.cpp: In function ‘int f(T) [with T = int]’:
foo.cpp:10:   instantiated from ‘const int S<int>::N’
foo.cpp:10:   instantiated from ‘int f(T) [with T = int]’
foo.cpp:14:   instantiated from here
foo.cpp:10: error: explicit instantiation of ‘S<int>::N’ but no definition available

但是为什么我收到了错误?

  1. 进行显式模板实例化声明的要点是,定义可以其他地方,但编译器(而不是链接器)会产生错误。 (在实际应用程序中,当前注释掉的显式实例化声明无论如何都会在另一个翻译单元中。)
  2. 在这种情况下,该值具有常量初始化程序,因此编译器理论上可以直接使用该值。
  3. 当我不进行显式模板实例化声明时,我(奇怪地)不必明确定义S<T>::N
  4. 这适用于Mac OS X 10.6.6上的g ++ 4.2.1。

2 个答案:

答案 0 :(得分:2)

extern template class S<int>;

我认为这一行会导致错误,因为它告诉编译器在某处查找S<int>显式实例化,但不存在显式实例化。因此错误。

一旦你评论这一行,我认为代码应该编译好。


编辑:

好吧,请看:http://www.ideone.com/oQnOi

正如我所说,它编译得很好!


编辑:

我认为$ 9.4.2 / 4(由 Mark B 引用)不适用于类模板的静态成员,因为$ 14.5.1.3 [temp。 static]不强制在命名空间范围内定义静态成员:

  

静态数据成员的定义   可以在命名空间范围中提供   包含静态的定义   会员的班级模板

示例如下,

template<class T> class X  { static T s; }; 
template<class T> T X<T>::s = 0;

注意,它没有说“必须提供”,而是“可能提供”。所以我认为在命名空间范围内类模板的静态成员的定义是可选的。

答案 1 :(得分:2)

从9.4.2 / 2开始:

  

静态数据的声明   其类定义中的成员不是   一个定义,可能是一个   除了cvqualified之外的不完整类型   无效。静态数据的定义   成员应出现在命名空间中   封闭成员类的范围   定义。在定义中   命名空间范围,名称   静态数据成员应具备资格   通过其类名使用::   操作

从9.4.2 / 4:

  

如果静态数据成员是const   整数或常数枚举类型,   它在课堂上的宣言   定义可以指定一个   constantinitializer是一个   积分常数表达式(5.19)。   在这种情况下,该成员可以出现在   内积分常数表达式   它的范围。该成员仍然是   如果是,则在命名空间范围内定义   用于程序和命名空间   范围定义不得包含   初始化程序。

根据这些参考文献,我们可以推断(“......仍然应该在9.4.2 / 4中定义......”)如果没有定义那么程序就没有格式良好。