以下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> >'
。
答案 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*)0
和nullptr
是有效的模板参数 “指向int的指针”的 template-parameter - end note ][...]