非类型(引用)模板参数和链接
Non-type (reference) template parameters and linkage
下面,
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
}
使用j
作为模板参数,GCC给出错误,而clang编译良好。
-
i
、j
的连锁关系是什么? - 为什么
const
/非const
有差异? - 谁正确?GCC还是clang?
正如Kerrek在评论中指出的那样,名称空间级别的const
变量具有内部链接(除非使用extern
关键字)。在c++ 03中,不能使用带有内部链接的指针或变量的引用作为非类型模板参数。这个限制在c++ 11中被取消了。看来你的gcc版本使用的是c++ 03规则,而clang编译器使用的是c++ 11规则。
14.3.2 [temp.arg。/1
对于非类型、非模板的模板形参, 模板形参应该是:
- […]
- 一个常量表达式(5.19),用于指定具有静态存储时间和外部或内部链接的对象的地址。或具有外部或内部链接的函数,包括函数模板和函数模板id,但不包括非静态类成员,表示为(忽略括号)&id-expression,除了那就是&如果名称指的是函数或数组,可以省略如果对应的模板参数为a,则省略参考;或
- […]
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]
对于非类型、非模板的模板参数应该是:
-…
-一个常量表达式(5.19),用于指定具有静态存储时间和外部或内部链接的完整对象的地址…
j
满足上述要求,应该允许作为非类型参数
这是一个bug,但是它是已知的(并且它还没有实现,至少在gcc 4.9之前)。
这是bug报告
我希望gcc 5.0实现这个功能,因为5.0增加了许多新的c++ 11特性。
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- C++线程找不到函数作为参数(链接器)
- 指向(数据)成员的指针作为非类型模板参数,例如具有自动存储持续时间/无链接
- 是否可以在调用链接器时强制 CMake 重新排序参数?
- 对可变参数函数的递归调用的链接器错误
- Clang 3.8 错误:参数 '-fuse-ld=gold-2.25' 中的链接器名称无效
- 在为 Java 编译动态链接文件时,我应该选择哪些 g++ 参数
- 解析参数值 - 字符串和链接值(类型字符串的链接值)与(特定类型的)变量
- 当用作模板参数时,功能指针是否需要指向具有外部链接的函数
- C 指针节点帮助 - 将参数复制到链接的列表节点更改该节点的不同部分
- 用一个参数计数圆形链接列表中的节点
- 链接列表发行了多个参数
- 将静态参数克隆到 std::fill 导致链接器失败
- 链接可变参数函数调用
- 如何在 Makefile 中正确包含 -wl、-rpath$ORIGIN 链接器参数?
- 函数与来自未命名命名空间的参数的链接
- 将模板类与引用非类型模板参数一起使用时出现链接器错误
- 链接列表加法/减法功能正在改变参数的值
- 将构造函数与 const char * 作为参数链接会产生意外的结果
- QList作为函数参数-链接错误-LNK2019