2016-03-16 40 views
2

以下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(主干254750):使用非类型参数的奇怪模板实例化错误

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> >(); 
} 

锵只IntSpec<>上的PtrSpec<>实例错误,但不是。这是一个编译器错误,标准中的含糊不清或者我在编写代码时总是需要考虑的东西?如有可能,请提供参考。

编辑:我进一步分析发现,两种编译了以下工作:

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> >(); } 

,但如果我改变&xnullptr我得到implicit instantiation of undefined template 'PtrSpec<MetaValue<int *, nullptr> >'铿锵++。

+0

文件铿锵的错误。他们会想要解决这个问题。 – Graznarak

+0

@Graznarak Nah,没有足够的动机atm。 – jotik

回答

4

此代码应该正常工作,符合标准。从N3242

§14.3.2/ 1:

模板参数的用于非类型,非模板模板参数 应是以下之一:

[...]

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

[...]

§14.3.2/ 5:

下列转换上用作 非类型模板的每个表达式进行 - 参数。如果非类型模板参数不能被 转换为对应模板参数的类型那么 程序是格式不正确的。类型的指针

[...]

  • 用于非类型模板参数到对象, 资格转换(4.4)和所述阵列到指针转换 (4.2)是应用;如果模板参数的类型为std::nullptr_t, ,则应用空指针转换(4.10)。 [注: [...]然而,无论 (int*)0nullptr有效模板参数的非类型 模板参数类型的“指针为int。” - 注完]

[...]

+1

任何想法为什么叮当失败,你呢? – jotik