非类型引用形参/实参
Non-type reference parameter/argument
为什么非类型引用的模板实参不能是另一个引用(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),用于指定具有静态存储时间和外部或内部链接的对象或具有外部或内部链接的函数(包括函数模板)的地址和函数模板id,但不包括非静态类成员,表示为(忽略括号)&id-表达式,除了&引用函数或数组的可以省略,引用模板形参的可以省略;还是…
(。4)
[注意:临时值,未命名的左值和没有链接的命名左值是不可接受的模板参数当对应的模板参数具有引用类型时
(5)-对于object引用类型的非类型模板形参,不应用任何转换。提及的类型引用的To可能比模板参数的类型(在其他方面相同)更符合cv。模板形参直接绑定到模板实参,模板实参应该是左值。
p
应该被认为是左值,不是吗?我能想到的唯一一件事是可能缺乏参考链接,但添加extern int& p = x
也没有解决它。
这与我之前在评论中链接到的constexpr函数失败的先前问题模板实例化有关,尽管您的情况不同。
看起来这个例子以前是不允许的,但是通过提案允许对所有以:
开头的非类型模板参数进行常量求值,从而增加了对c++ 1z的支持。指针、引用和指向对象的指针的语法限制成员很笨拙,妨碍了合理的重构。[…]这种限制的历史原因很可能是c++以前没有一个足够强大的规范指针、引用或指针到成员类型的常量表达式。然而,情况已不再如此。[…]
似乎与您的情况相关的具体变化是对c++标准部分草案14.3.2
模板非类型参数[temp.arg]的重新措辞。nontype]/p1:
非类型、非模板模板形参的模板实参必须是:
[…]
- 一个常量表达式(5.19),用于指定具有静态存储时间的完整对象的地址外部或内部连杆或一个函数带有外部或内部连杆,包括函数模板和函数模板id,但不包括非静态类成员,表示(忽略括号)为,Id-expression,其中Id-expression是对象或函数的名称,但,如果名称指的是函数或数组,可以省略;如果对应Template-parameter是一个引用;或
[…]
:
非类型模板形参的模板实参必须是的转换常量表达式(5.20)模板参数的类型。对于引用类型或指针类型的非类型模板形参常量表达式的值不能指向(或者对于指针类型,不能是的地址):
a子对象(1.8),
一个临时对象(12.2),
字符串字面值(2.13.5),
类型标识表达式的结果(5.2.8),或者
一个预定义的 func 变量(8.4.1)。
和section 5.20
常量表达式的变化[expr。Const]/p4有以下关于转换常量表达式的段落,它开始于:
转换后的T类型常量表达式是隐式转换为T类型的表达式,其中转换后的Expression是常量表达式,隐式转换序列只包含
。
和这个特别添加:
[…]和引用绑定(如果有的话)直接绑定的地方[…]
注意,clang的当前头版本将以c++ 1z模式编译你的代码,请查看现场。
使用的是N4268的更新版本,clang c++ 1z实现状态部分表明本文得到了clang 3.6的支持。此代码仅适用于clang 3.6及更高版本的c++ 1z模式
使用N4268引入的简化措辞(现在在WD中),
对于非类型模板形参, 模板实参应该是A模板参数类型的转换常量表达式(5.20)。对于引用[…]类型的非类型模板参数常量表达式的值不能引用[…]:[…不适用…的情况]
"转换后的常量表达式"定义在[expr.const]/4:
类型为
T
的转换后的常量表达式是一个表达式,隐式转换为类型T
,其中转换后的表达式为a常量表达式和隐式转换序列包含只有[…]和引用绑定(如果有的话)直接绑定的地方。
显然,引用直接绑定。x
和p
在这种情况下是常量表达式吗?
[expr.const]/5:
常量表达式是一个glvalue核心常量表达式其值指的是一个实体,该实体是常量表达式(定义如下),或[…]
允许的常量表达式的结果在下一段定义为
…具有静态存储时间的对象,该对象不是临时对象或[…]
x
和p
确实指的是具有静态存储持续时间的对象,但它们是给定上下文中的核心常量表达式吗?答案是肯定的:只要它们的值(或p
引用的对象的值)没有被表达式检查,一切都很好,即使是p
:
一个条件表达式
的变量或数据成员e
是一个核心常量表达式,除非e
的求值[…]将求值以下表达式之一:-一个id-表达式引用类型,除非引用之前有初始化和
- 用常量表达式
初始化
x
作为p
的初始化项是一个常量表达式(正如它是int&
的有效模板参数一样),因此p
作为模板参数也是一个常量表达式。
- 非类型引用形参/实参
- 哪种方法更适合为函数提供编译时间常数?函数实参与模板形参
- 传递boost::函数,该函数接受一个模板实参作为默认为NULL的形参
- 当实参是初始化列表而形参是引用时,重载解析
- 使用模板模板形参时,模板实参推导失败
- 为什么模板非类型形参指针和引用实参需要是全局的
- 将函数形参的实参解包到c++模板类
- 从模板实参的子类中推断函数模板形参
- 如何将实参传递给此形参
- 带默认模板实参的形参包
- c++函数中理论上可以作为形参传递多少个实参
- 在c++中真的不可能跳过带有默认实参的模板形参吗?为什么语法不这么认为?
- c++默认实参值使用另一个形参的值
- 在模板中使用模板形参作为实参
- 将非const引用使用auto-keyword声明的lambda作为实参传递给std::函数形参类型
- 模板继承:没有依赖模板形参的实参
- 通过函数实参而不是模板形参获取元组的元素
- 基于模板形参的Enum实参
- 在函数实参中使用模板形参不适用gcc4.8
- 函数指针的形参类型的模板实参演绎涉及未演绎的形参包