[expr.ref]/2 中的左值到右值转换

Lvalue-to-rvalue conversion in [expr.ref]/2

[expr.ref]/2:

For the first option (dot) the first expression shall be a glvalue having complete class type. For the second option (arrow) the first expression shall be a prvalue having pointer to complete class type. The expression E1->E2 is converted to the equivalent form (*(E1)).E2; the remainder of [expr.ref] will address only the first option (dot).68 In either case, the id-expression shall name a member of the class or of one of its base classes. [ Note: Because the name of a class is inserted in its class scope (Clause [class]), the name of a class is also considered a nested member of that class.  — end note ] [ Note: [basic.lookup.classref] describes how names are looked up after the . and -> operators.  — end note ]

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

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

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

A prvalue of type T can be converted to an xvalue of type T. This conversion initializes a temporary object (15.2) of type T from the prvalue by evaluating the prvalue with the temporary object as its result object, and produces an xvalue denoting the temporary object. T shall be a complete type. [Note: If T is a class type (or array thereof), it must have an accessible and non-deleted destructor; see 15.4. — end note] [Example:

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

end example]

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

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