Is class member access through a pointer to data member considered a member access expression?

Viewed 103

One of the rules explaining how the decltype keyword works states that:
If the argument is [...] an unparenthesized class member access expression, then decltype yields the type of the entity named by this expression. (https://en.cppreference.com/w/cpp/language/decltype)
However, consider the following example (pseudo-code for brevity):

struct X {
    int a;
};

X x;
int X::* ptr = &X::a;
std::is_lvalue_reference<decltype(x.*ptr)>::value; //Evaluates to 1. The type is int&
std::is_rvalue_reference<decltype(X().*ptr)>::value; //Evaluates to 1. The type is int&&

This implies that accessing a class member through a pointer to member is not a class member access expression. It's treated as if it was just a normal expression, for which the rule I quoted doesn't apply.
Therefore, my question is: how can I know what exactly counts as a class member access expression for the purpose of decltype? What source should I look into to find a precise definition?

1 Answers

Class member access is defined in [expr.ref].

It is:

A postfix expression followed by a dot . or an arrow ->, optionally followed by the keyword template, and then followed by an id-expression

x.y is class member access, get().y is class member access, x.template y<int>() is class member access, etc.

But neither x.*ptr nor X().*ptr are, because of the *. They are pointer-to-member operators, which are described in [expr.mptr.oper]. They also have different (lower) precedence from class member access: x.*y.z evaluates as x.*(y.z).

Related