条件表达式中的右值引用
Rvalue references in a conditional expression
typedef decltype(true ? (long&&)0 : (long&&)0) T;
T 应该是什么?
根据 gcc (4.7),它是long
.根据叮当(树干)的说法,这是long&&
.这种差异导致 clang 无法编译使用 gcc 4.7 的 libstdc++ 的代码。谁是对的?
更新:正如ildjarn指出的那样,Clang是对的,正如Richard Smith指出的那样,libstdc++错误是由于标准中的错误造成的。以下是相关的 GCC 错误,以及相关的缺陷报告。
Clang 是对的。N3337 §7.1.6.2/4:
decltype(e)
表示的类型定义如下:
- 如果
e
是无括号的 ID 表达式或无括号的类成员访问,则decltype(e)
是e
命名的实体的类型。如果没有这样的实体,或者如果e
命名一组重载函数,则程序格式不正确;- 否则,如果
e
是x值,则decltype(e)
T&&
,其中T
是e
的类型;- 否则,如果
e
是左值,则decltype(e)
T&
,其中T
是e
的类型;- 否则,
decltype(e)
是e
的类型。
decltype
说明符的操作数是未计算的操作数。
§5/6:
[ 注意:如果表达式是:
调用
通常,此规则的效果是,命名的右值引用被视为左值,对对象的未命名右值引用- 函数的结果,无论是隐式还是显式调用,其返回类型是对对象类型的右值引用,
- 强制转换为对对象类型的右值引用,
类成员访问表达式,- 该表达式指定非引用类型的非静态数据成员,其中对象表达式是 x值,或
- 一个指向成员
.*
指针表达式,其中第一个操作数是 x值,第二个操作数是指向数据成员的指针。被视为 x值;对函数的右值引用被视为左值,无论是否命名。
我之前很谨慎,文字0
可能会以某种方式阻止它在这种情况下成为对象类型,但 §3.9/8 澄清了事情:
对象类型是(可能符合 cv 条件的)类型,它不是函数类型、不是引用类型,也不是 void 类型。
条件运算符不影响此处的任何内容 – §5.16/4:
如果第二个和第三个操作数是相同值类别的 glvalue 并且具有相同的类型,则结果属于该类型和值类别,如果第二个或第三个操作数是位字段,或者如果两者都是位字段,则结果为位字段。
在这种情况下,两者具有相同的值类别 (xvalue),并且 x 值是 glvalues。
相关文章:
- 函数返回的 rvalue 引用(表达式)是 xvalue - 但没有标识?
- 仅通过引用捕获的 lambda 表达式是否保证不会抛出?
- C++在构造函数处用表达式初始化引用
- C++ 解决方法:"从类型"B*"的表达式初始化类型"C*&"的引用无效"
- 获取表达式的类型(包括引用C++)
- lambda 表达式中引用捕获的 constexpr 变量和非显式捕获的 constexpr 变量之间的区别
- 通过引用传递表达式与通过引用传递变量
- 常量表达式中引用类型的变量
- 将函数的引用和 lambda 表达式作为参数传递时有什么区别?
- 在给定表达式的情况下返回对类型的引用时出错:“cond ?*这个 : 投掷()'
- 引用初始化和常量表达式
- 为什么返回非引用类型的函数表达式被认为是prvalues而不是xvalues
- C++:从类型"int*"的表达式初始化类型"const int*&"的引用无效
- Boost正则表达式:链接时未定义的引用
- 关于解引用运算符是否在表达式中产生对象对值的定义不明确
- 错误:从类型"testGetter* const"的表达式初始化类型"const testGetter*&"的引用无效
- 尝试使用 uint*& 作为常量单元*&失败:从类型"uint8_t"的表达式初始化类型"const uint8_t*&"的引用无效
- C++常量引用允许从表达式进行更改
- 为什么将表达式强制转换为对函数的右值引用是左值
- 错误:从类型"const int"的表达式初始化类型"int"的引用无效