Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/146.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 没有可用于具有初始值设定项的静态常量成员的定义?_C++_Templates_C++11_Instantiation - Fatal编程技术网

C++ 没有可用于具有初始值设定项的静态常量成员的定义?

C++ 没有可用于具有初始值设定项的静态常量成员的定义?,c++,templates,c++11,instantiation,C++,Templates,C++11,Instantiation,鉴于: 模板 结构{ 静态int常数N=1; }; 外部模板类; 模板 int f(T n){ 返回n+S::n;//第10行 } int main(){ 返回f(1);//第14行 } //模板类S;//故意注释掉以触发错误 我得到: template<class T> struct S { static int const N = 1; }; extern template class S<int>; template<class T> int

鉴于:

模板
结构{
静态int常数N=1;
};
外部模板类;
模板
int f(T n){
返回n+S::n;//第10行
}
int main(){
返回f(1);//第14行
}
//模板类S;//故意注释掉以触发错误
我得到:

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:intf(T)[with T=int]函数中:
foo.cpp:10:从“const int S::N”实例化
foo.cpp:10:从“intf(T)[带T=int]实例化”
foo.cpp:14:从这里实例化
foo.cpp:10:错误:“S::N”的显式实例化,但没有可用的定义
但是为什么我会得到错误

  • 执行显式模板实例化声明的目的是使定义可以在其他地方,但编译器(而不是链接器)会给出错误。(在实际应用程序中,当前注释掉的显式实例化声明无论如何都会在另一个翻译单元中。)
  • 在这种情况下,该值有一个常量初始值设定项,因此理论上编译器可以直接使用该值
  • 当我不执行显式模板实例化声明时,我(奇怪的是)不必显式定义
    S::N
  • 这是在Mac OS X 10.6.6上的g++4.2.1中实现的。

    extern模板类;
    
    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
    
    我认为这行代码会导致错误,因为它告诉编译器在某处查找
    S
    的显式实例化,但不存在显式实例化。因此出现了错误

    一旦你注释了这一行,我认为代码应该编译得很好


    编辑:

    那么看这个,

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


    编辑:

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

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

    下面的例子是:

    extern template class S<int>;
    
    模板类X{static ts;};
    模板tx::s=0;
    
    注意,它没有说“必须提供”,而是说“可能提供”。因此,我认为在命名空间范围内定义类模板的静态成员是可选的。

    来自9.4.2/2:

    静态数据的声明 其类定义中的成员不是 一个定义,可以是 不完整的类型,但不符合条件 无效的静态数据的定义 成员应出现在名称空间中 包含成员类的范围 定义。在 命名空间范围,名称空间的名称 静态数据成员应是合格的 通过其类名使用:: 接线员

    从9.4.2/4开始:

    如果静态数据成员为常量 整型或常量枚举类型, 它在课堂上的声明 定义可以指定 康斯坦丁化剂,应为 积分常数表达式(5.19)。 在这种情况下,成员可以出现在 内的积分常数表达式 它的范围。该成员仍应为 在命名空间范围中定义,如果 在程序和命名空间中使用 范围定义不应包含 初始化器


    从这些引用中,我们可以推断(“…仍应定义…”在9.4.2/4)中,如果未定义,则程序的格式不正确。

    您可以使用
    enum{N=1}
    而不是
    静态常量
    @KennyTM:这并不能回答问题。显然,这个例子是我真实代码的一个缩减的例子。真正的代码需要一个unsigned long集,设置为~0,而且,恕我直言,枚举不能是“unsigned”的。我认为这只是一个编译器错误。它在mingw下用g++4.4.0编译的很好。我觉得这是个编译器问题。Comeau和VC++似乎没有任何问题(尽管如果你取消注释最后一行,VC++抱怨该实例化没有
    extern
    ,因此它与前一行不匹配。你也可以将其解释为“可能提供”与“可能根本不提供”,而不是相反的意思“可能在其他地方提供”。该标准是否允许在其他地方提供?@Oli:我将其解释为“可能根本不提供”。我的意思是,命名空间范围中的定义是可选的。
    template<class T> class X  { static T s; }; 
    template<class T> T X<T>::s = 0;