为什么非类型引用的模板参数不能是另一个引用(g ++ 4.8.1):
template <int& N> void test() { }
int x = 5;
int& p = x;
int main(){
test<x>(); //compiles fine
test<p>(); //error: could not convert template argument 'p' to 'int&'|
}
我无法看到标准p
中的哪些内容违反了任何内容,这些似乎是最相关的部分(N3337):
不应该将[14.3.2] [.1]非类型非模板模板参数的模板参数应为以下之一:
- 对于整数或枚举类型的非类型模板参数,是模板参数类型的转换常量表达式(5.19);或
- 非类型模板参数的名称;或
- 一个常量表达式(5.19),用于指定具有静态存储持续时间和外部或内部链接的对象的地址,或具有外部或内部链接的函数,包括函数模板 和函数template-ids但不包括非静态类成员,表示(忽略括号)为&amp; id-expression,除了&amp;如果名称引用函数或数组,则可以省略,如果相应的模板参数是引用,则应省略;或者......
[。4]
[注意:Temporaries,未命名的左值和没有链接的命名左值是不可接受的模板参数 当相应的模板参数具有引用类型时。
[5]
- 对于对象类型引用的非类型模板参数,不适用任何转换。提到的类型 通过引用,可以比模板参数的(否则相同)类型更加cv限定。 template-parameter直接绑定到template-argument,它应该是一个 左值。
p
视为左值吗?我能想到的另一件事可能是缺少引用的链接,但添加extern int& p = x
也没有解决它。
答案 0 :(得分:3)
这与我之前在评论中链接的上一个问题template instantiation with constexpr function failure有关,尽管您的情况不同。
看起来以前不允许这个例子,但是通过提案Allow constant evaluation for all non-type template arguments将支持添加到C ++ 1z中,该提案打开:
指针,引用和指针的语法限制 成员很尴尬,阻止合理的重构。 [...] 限制的历史原因很可能是C ++ 以前没有足够强大的规格 指针,引用或指向成员类型的常量表达式。 但是,情况已不再如此。 [...]
与您的案例相关的具体更改是草案C ++标准部分14.3.2
模板非类型参数[temp.arg.nontype] / p1的重写:
非类型非模板模板参数的模板参数应为以下之一:
[...]
- 一个常量表达式(5.19),用于指定具有静态存储持续时间的完整对象的地址 和外部或内部联系或具有外部或内部联系的功能,包括功能 模板和函数template-id但不包括非静态类成员,表示(忽略括号) 作为&amp; id-expression,其中id-expression是对象或函数的名称,除了 &安培;如果名称引用函数或数组,则可以省略,如果相应则应省略 template-parameter是一个引用;或
[...]
为:
非类型模板参数的模板参数应为转换后的常量表达式(5.20) template-parameter的类型。对于引用或指针类型的非类型模板参数, 常量表达式的值不应引用(或指针类型,不应是地址):
子对象(1.8),
临时对象(12.2),
字符串文字(2.13.5),
- 的结果
typeid表达式(5.2.8)或
预定义的 func 变量(8.4.1)。
和节5.20
的更改常量表达式[expr.const] / p4在转换的常量表达式上有以下段落,它开始于:
T类型的转换常量表达式是一个表达式,隐式转换为类型T,其中转换后的表达式 expression是一个常量表达式,隐式转换序列只包含
特别增加了这一点:
[...]并且引用绑定(如果有的话)直接绑定[...]
注意,clang的当前头版本用C ++ 1z模式see it live编译代码。
N4268的更新版本是应用的版本,clang C++1z implementation status section表示本文是clang 3.6的支持。此代码仅适用于clang 3.6及更高版本的C ++ 1z模式。
答案 1 :(得分:2)
使用N4268(现在在WD中)引入的简化措辞,
非类型模板参数的 template-argument 应为a 转换为模板参数 类型的常量表达式(5.20)。对于参考[...]类型的非类型模板参数, 常数表达式的值不应指[...]:[......不适用的情况......]
“转换常量表达式”在[expr.const] / 4中定义:
T
类型的转换常量表达式是一个表达式, 隐式转换为类型T
,其中转换后的表达式为a 常量表达式和隐式转换序列包含 只有[...]和引用绑定(如果有的话)直接绑定。
显然,参考文献直接绑定。在此上下文中是x
和p
常量表达式吗?
[expr.const] / 5:
常量表达式是glvalue核心常量表达式 其值是指一个允许的结果的实体 常量表达式(定义如下)或[...]
常量表达式的允许结果在下一段中定义为
...具有静态存储持续时间的对象,该对象不是临时对象或[...]
x
和p
确实引用具有静态存储持续时间的对象,但它们是给定上下文中的核心常量表达式吗?答案是肯定的:只要他们的值(或对象的值p
所引用的)没有被表达式检查,它就不是,一切都很好,即使是p
:
条件表达式
e
是核心常量表达式,除非e
[...]的评估将评估以下表达式之一:- 引用其变量或数据成员的 id-expression 引用类型,除非引用具有先前的初始化和 任
- 使用常量表达式初始化
x
,因为p
的初始化程序是一个常量表达式(就像它是int&
的有效模板参数一样),因此p
作为模板参数也是一个不变的表达。
请注意,Clang as of version 3.6会将您的代码段编译好。