以下,
int i{3};
const int j{3};
extern const int k{3};
template <typename T, T&>
void f() {}
int main()
{
f<int, i>(); // OK
f<int const, j>(); // not valid template argument: 'j' has not external linkage
f<int const, k>(); // OK
}
GCC在使用j
作为模板参数时出错,而clang编译正常。
i
,j
的链接是什么?const
/非 - const
?答案 0 :(得分:5)
正如Kerrek在评论中指出的,名称空间级别const
变量具有内部链接(除非您使用extern
关键字)。在C ++ 03中,您不能将具有内部链接的变量的指针或引用用作非类型模板参数。在C ++ 11中取消了这一限制。看来你的gcc版本是按C ++ 03规则播放的,而clang编译器则是使用C ++ 11规则。
14.3.2 [temp.arg.nontype] / 1
非类型非模板模板参数的 template-argument 应为以下之一:
- [...]
- 一个常量表达式(5.19),用于指定具有静态存储持续时间和外部或内部链接的对象的地址 或具有外部或内部联系的功能,包括功能 模板和函数template-id但不包括非静态类 成员,表达(忽略括号)为&amp; id-expression,除了 那&amp;如果名称引用函数或数组,则可以省略 如果相应的模板参数是a,则应省略 参考;或
- [...]
答案 1 :(得分:3)
i
具有外部链接,而j
具有内部链接。这些规则列在§3.5[basic.link]
4 未命名的命名空间或直接或间接在未命名的命名空间内声明的命名空间具有内部链接。 所有其他名称空间都有外部链接。具有名称空间作用域的名称上面没有给出内部链接,如果是名称,则与封闭名称空间具有相同的链接 - 一个变量;或
- ......
全局命名空间具有外部链接,因此i
也具有外部链接(因为它未明确声明为具有内部链接)。
3 具有命名空间范围(3.3.6)的名称具有内部链接(如果它是名称) - ......
- 显式声明 const 或 constexpr 的非易失性变量,既未明确声明 extern 也未声明具有外部链接< /强>;或
- ......
j
显式声明为const
而未声明为extern
,因此它具有内部链接。
我认为clang在这种情况下是正确的,因为§14.3.2/ 1 [temp.arg.nontype]
非类型非模板模板参数的 template-argument 应为以下之一:
- ......
- 一个常量表达式(5.19),用于指定具有静态存储持续时间和外部或内部链接的完整对象的地址......
j
满足上述要求,应该允许作为非类型参数。
答案 2 :(得分:2)