0

[expr.ref]/2

对于第一个选项(点),第一个表达式应是具有完整类类型的泛左值。对于第二个选项(箭头),第一个表达式应是具有指向完整类类型的指针的纯右值。表达式 E1->E2 被转换为等价形式 (*(E1)).E2;[expr.ref] 的其余部分将仅处理第一个选项(点)。68在任何一种情况下,id 表达式都应命名该类或其基类之一的成员。[ 注意:因为类名插入到其类范围内(子句 [class]),所以类名也被认为是该类的嵌套成员。— end note ] [ 注意:[basic.lookup.classref] 描述了如何在 . 和 -> 运算符。——尾注]

根据本段,在p下面的代码段中应用了左值到右值的转换。但不适用于a. 为什么标准为第一个选项(点)规定了一个左值,为第二个选项(箭头)规定了一个纯右值?

struct A{ void f() {} };
A a;
A* p = new A;
int main() {
    a.f();
    p->f();
}
4

1 回答 1

3

请记住,prvalues 可以通过临时实现转换 [conv.rval] 转换为 xvalues:

类型的纯右值T可以转换为类型的 xvalue T。此转换通过以临时对象作为其结果对象评估纯右值,从纯右值初始化一个类型的临时对象(15.2)T,并产生一个表示临时对象的 xvalue。T应该是一个完整的类型。[注意:如果T是类类型(或其数组),它必须有一个可访问且不可删除的析构函数;见 15.4。—尾注] [示例

struct X { int n; };
int k = X().n;
// OK, X() prvalue is converted to xvalue

结束示例]

在引入这种新的右值到左值转换之前,C++14 没有将后缀表达式限制为右值。

关于这一点,C++11 是第一个通过(当时)新的右值引用类型实现用户可定义、无约束的右值到左值转换的修订版:auto&& x = f();将右值f()变成 xvalue x

于 2017-03-26T13:59:37.583 回答