非类型引用参数/参数 [英] Non-type reference parameter/argument

查看:137
本文介绍了非类型引用参数/参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么非类型引用的模板参数不能是另一个引用(g ++ 4.8.1):

  template< int& N> void test(){} 

int x = 5;
int& p = x;

int main(){
test< x>(); // compiles fine
test< p>(); //错误:无法将模板参数'p'转换为'int&'|
}

我看不到标准 p 违反任何内容,这些似乎是最相关的部分(N3337):


[14.3.2] 1]非类型非模板模板参数的模板参数应为以下之一:



- 对于非类型模板参数为整数或枚举类型,模板参数类型的转换常数表达式(5.19)或



- 非类型模板参数的名称;或



- 常量表达式(5.19),指定具有静态存储持续时间和外部或内部链接或具有外部或内部链接的函数的对象的地址,模板
和函数模板id,但不包括非静态类成员,表示为(忽略括号)为& id表达式,除了&如果名称引用函数或数组,则可以省略,并且如果相应的模板参数是引用则将被省略;或.....



[。4]



[注意:临时,未命名左值没有链接的左值不可接受的模板定义
当相应的模板参数具有引用类型时。



[。5]



- 对于对象的类型引用的非类型模板参数,不适用转换。引用引用的
类型可能比模板引用的(否则相同)类型更具cv限定。
模板参数直接绑定到模板参数,它将是一个
左值。


p 应该被认为是一个左值不应该吗?我可以想到的唯一的另一件事是可能缺乏参考链接,但添加 extern int& p = x 也没有修复它。

解决方案

这与上一个问题有关模板实例化与constexpr函数失败,我链接到一个以前在注释,虽然你的情况是不同的。



它看起来的例子是以前不允许,但支持通过提议添加到C ++ 1z 允许对所有非类型模板参数进行常量评估,它以:


开头的指针的句法限制,引用和指向
成员的指针是尴尬的,并阻止合理的重构。 [...]
限制的历史原因很可能是C ++
以前没有足够强的规范用于
指针,引用或指针成员的常量表达式类型。
然而,不再是这样。 [...]


与您的案例相关的具体更改是修改C ++标准草案部分 14.3.2 模板非类型参数[temp.arg.nontype] / p1从:


非类型非模板模板参数的模板参数应为以下之一:



[...]




  • 常量表达式(5.19),指定具有静态存储持续时间
    的完整对象的地址以及外部或内部链接或具有外部或内部链接的函数,包括函数
    模板和函数模板id,但不包括非静态类成员,表示(忽略括号)
    as& id-expression,其中id-expression是对象或函数的名称,除了
    &如果名称引用函数或数组,则可以省略,如果相应的
    模板参数是引用,则省略;或



[...]


到:


非类型模板参数的模板参数必须是$ b的转换常数表达式$ b模板参数的类型。对于引用或指针类型的非类型模板参数,常量表达式的
值不应引用(或对于指针类型,不应为的地址):




  • 一个子对象(1.8),


  • / p>


  • 字符串文字(2.13.5),


  • (5.2.8)或


  • 预定义的 func 变量(8.4.1)。



并更改 5.20 常量表达式[expr .const] / p4在转换常量表达式上有以下段落:


类型T的转换常量表达式是一个表达式,隐式转换为类型T,其中转换的
表达式是常量表达式,隐式转换序列仅包含


特别是添加了:


[...] / p>

注意,clang的当前头版本以C ++ 1z模式编译您的代码,查看它现场

更新版本的 N4268 是应用的, clang C ++ 1z实现状态部分表示本文是来自clang 3.6的支持。此代码仅适用于Clang 3.6及更高版本的C ++ 1z模式。


Why is it that the template argument of a non-type reference cannot be another reference (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&'|  
}

I can't see where from the standard p is violating anything, these seemed the most relevant sections (N3337):

[14.3.2] [.1] A template-argument for a non-type, non-template template-parameter shall be one of:

— for a non-type template-parameter of integral or enumeration type, a converted constant expression (5.19) of the type of the template-parameter; or

— the name of a non-type template-parameter; or

— a constant expression (5.19) that designates the address of an object with static storage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as & id-expression, except that the & may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; or .....

[.4]

[ Note: Temporaries, unnamed lvalues, and named lvalues with no linkage are not acceptable templatearguments when the corresponding template-parameter has reference type.

[.5]

— For a non-type template-parameter of type reference to object, no conversions apply. The type referred to by the reference may be more cv-qualified than the (otherwise identical) type of the templateargument. The template-parameter is bound directly to the template-argument, which shall be an lvalue.

p should be considered an lvalue shouldn't it? The only other thing I could think of was maybe a lack of linkage for references but adding extern int& p = x didn't fix it either.

解决方案

This is related to the previous question template instantiation with constexpr function failure which I linked to a while ago in the comments, although your case is different.

It looks the example was previously not allowed but support was added in to C++1z via the proposal Allow constant evaluation for all non-type template arguments which opens with:

the syntactic restrictions for pointers, references, and pointers to members are awkward and prevent reasonable refactorings. [...] The historical reason for the restriction was most likely that C++ previously did not have a sufficiently strong specification for constant expressions of pointer, reference, or pointer-to-member type. However, that is no longer the case. [...]

The specific changes that seems relevant to your case is the rewording of the draft C++ standard section 14.3.2 Template non-type arguments [temp.arg.nontype]/p1 from:

A template-argument for a non-type, non-template template-parameter shall be one of:

[...]

  • a constant expression (5.19) that designates the address of a complete object with static storage durationtion and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as & id-expression, where the id-expression is the name of an object or function, except that the & may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; or

[...]

to:

A template-argument for a non-type template-parameter shall be a converted constant expression (5.20) of the type of the template-parameter. For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):

  • a subobject (1.8),

  • a temporary object (12.2),

  • a string literal (2.13.5),

  • the result of a typeid expression (5.2.8), or

  • a predefined func variable (8.4.1).

and a change of section 5.20 Constant expressions [expr.const]/p4 has the following paragraph on converted constant expressions, which starts out:

A converted constant expression of type T is an expression, implicitly converted to type T, where the converted expression is a constant expression and the implicit conversion sequence contains only

and this in particular was added:

[...] and where the reference binding (if any) binds directly [...]

Note, the current head version of clang compiles your code in C++1z mode, see it live.

The updated version of the N4268 was the one applied and clang C++1z implementation status section indicates this paper was support from clang 3.6. This code only works in C++1z mode for clang 3.6 and greater.

这篇关于非类型引用参数/参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆