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 ]
According to this paragraph, the lvalue-to-rvalue conversion is applied to p
in the snippet below. But it is not applied to a
. Why does the standard prescribe a glvalue for the first option (dot) and a prvalue for the second option (arrow)?
struct A{ void f() {} };
A a;
A* p = new A;
int main() {
a.f();
p->f();
}
.
or->
is an LValue or RValue. If neither is overloaded it must be an LValue (or would not produce an address which in turn is absolutly necessary to apply the "offset" of the right expression). The->
may be overloaded. Due to the implementation of the overloaded->
operator an RValue on left side may become sufficient. (However, I struggle to imagine a practical example - probably my lack of fantasy.) Operator.
may never be overloaded (its forbidden by the standard). – Scheff's Cat.
to rvalues. – Nicol Bolasstring("foo").c_str()
. That's legal, though the return value cannot be used outside of the overall statement that it appears in. – Nicol Bolasstring("foo")
andstd::string()
are prvalues. At least, they were in C++14. – aschepler