奇怪的模板实例化bug与非类型参数

时间:2016-03-16 10:29:13

标签: c++ c++11 g++ clang++ compiler-bug

以下C ++ 11代码使用g ++ 4.7.4,g ++ 4.8.5,g ++ 4.9.3和g ++ 5.3.0编译,但不能使用clang ++ 3.7.1或clang ++ 3.8.0(trunk 254750)编译:< / p>

template <typename F, F f> struct MetaValue {};

template <typename T> class IntSpec;
template <int V> class IntSpec<MetaValue<int, V> > {};

// note: template is declared here:
template <typename T> class PtrSpec;
template <void * V> class PtrSpec<MetaValue<void *, V> > {};

int main() {
  IntSpec<MetaValue<int, 0> >();

  // implicit instantiation of undefined template 'PtrSpec<MetaValue<void *, nullptr> >'
  PtrSpec<MetaValue<void *, nullptr> >();
}

仅对PtrSpec<>的实例化而不是IntSpec<>的实例化时出错。这是编译器错误,标准中的歧义还是我在编写代码时总是需要考虑的问题?如果可能,请提供参考。

编辑:我的进一步分析发现以下两种编译器都有效:

template <typename F, F f> struct MetaValue {};

// note: template is declared here:
template<typename T> class PtrSpec;
template <int * V> class PtrSpec<MetaValue<int *, V> > {};

extern int x;

int main() { PtrSpec<MetaValue<int *, &x> >(); }

但如果我将&x更改为nullptr,我会使用clang ++获得implicit instantiation of undefined template 'PtrSpec<MetaValue<int *, nullptr> >'

1 个答案:

答案 0 :(得分:4)

此代码应该正常,符合标准。来自N3242

<强>§14.3.2/ 1:

  

非类型非模板模板参数的模板参数   应该是以下之一:

     

[...]

     
      
  • 一个求值为空指针值的常量表达式(4.10);或
  •   
     

[...]

<强>§14.3.2/ 5:

  

对用作a的每个表达式执行以下转换   非类型模板参数。如果不能使用非类型 template-argument   转换为相应的模板参数的类型然后   节目形成不良。

     

[...]

     
      
  • 表示对象类型指针的非类型模板参数,   资格转换(4.4)和数组到指针的转换   (4.2)适用;如果 template-argument 的类型为std::nullptr_t,   应用空指针转换(4.10)。 [注意: [...]但是,两者都有   对于非类型,(int*)0nullptr是有效的模板参数   “指向int的指针”的 template-parameter - end note ]
  •   
     

[...]