[expr.prim.id] (original) (raw)
7 Expressions [expr]
7.5 Primary expressions [expr.prim]
7.5.5 Names [expr.prim.id]
7.5.5.1 General [expr.prim.id.general]
If an id-expression E denotes a non-static non-type member of some class C at a point where the current class ([expr.prim.this]) is X and
- E is potentially evaluated orC is X or a base class of X, and
- E is not the id-expression of a class member access expression ([expr.ref]), and
- if E is a qualified-id,E is not the un-parenthesized operand of the unary & operator ([expr.unary.op]),
the id-expression is transformed into a class member access expression using (*this) as the object expression.
[Note 2:
If C is not X or a base class of X, the class member access expression is ill-formed.
Also, if the id-expression occurs within a static or explicit object member function, the class member access is ill-formed.
— _end note_]
This transformation does not apply in the template definition context ([temp.dep.type]).
If an id-expression E denotes a member M of an anonymous union ([class.union.anon]) U:
- If U is a non-static data member,E refers to M as a member of the lookup context of the terminal name of E(after any implicit transformation to a class member access expression).
[Example 1:
o.x is interpreted as o.u.x, where u names the anonymous union member.
— _end example_] - Otherwise, E is interpreted as a class member access ([expr.ref]) that designates the member subobject M of the anonymous union variable for U.
[Note 3:
Under this interpretation, E no longer denotes a non-static data member.
— end note_]
[_Example 2:
N::x is interpreted as N::u.x, where u names the anonymous union variable.
— _end example_]
An id-expression that denotes a non-static data member or implicit object member function of a class can only be used:
- as part of a class member access (after any implicit transformation (see above)) in which the object expression refers to the member's class or a class derived from that class, or
- to form a pointer to member ([expr.unary.op]), or
- if that id-expression denotes a non-static data member and it appears in an unevaluated operand.
[Example 3: struct S { int m;};int i = sizeof(S::m); int j = sizeof(S::m + 42); — _end example_]
For an id-expression that denotes an overload set, overload resolution is performed to select a unique function ([over.match], [over.over]).
[Note 4:
A program cannot refer to a function with a trailing requires-clausewhose constraint-expression is not satisfied, because such functions are never selected by overload resolution.
[Example 4: template<typename T> struct A { static void f(int) requires false;};void g() { A<int>::f(0); void (*p1)(int) = A<int>::f; decltype(A<int>::f)* p2 = nullptr; }
In each case, the constraints of f are not satisfied.
In the declaration of p2, those constraints need to be satisfied even thoughf is an unevaluated operand.
— _end example_]
— _end note_]
7.5.5.2 Unqualified names [expr.prim.id.unqual]
The terminal name of a construct is the component name of that construct that appears lexically last.
If naming the entity from outside of an unevaluated operand within Swould refer to an entity captured by copy in some intervening lambda-expression, then let E be the innermost such lambda-expression.
- If there is such a lambda-expression and if P is in E's function parameter scope but not its parameter-declaration-clause, then the type of the expression is the type of a class member access expression ([expr.ref]) naming the non-static data member that would be declared for such a capture in the object parameter ([dcl.fct]) of the function call operator of E.
[Note 3:
If E is not declared mutable, the type of such an identifier will typically be const qualified.
— _end note_]
If the entity is a template parameter object for a template parameter of type T ([temp.param]), the type of the expression is const T.
In all other cases, the type of the expression is the type of the entity.
[Note 4:
The type will be adjusted as described in [expr.type]if it is cv-qualified or is a reference type.
— _end note_]
The expression is an xvalue if it is move-eligible (see below); an lvalue if the entity is a function, variable, structured binding, data member, or template parameter object; and a prvalue otherwise ([basic.lval]); it is a bit-field if the identifier designates a bit-field.
[Example 1: void f() { float x, &r = x;[=]() -> decltype((x)) { decltype(x) y1; decltype((x)) y2 = y1; decltype(r) r1 = y1; decltype((r)) r2 = y2; return y2;};[=](decltype((x)) y) { decltype((x)) z = x; };[=] { [](decltype((x)) y) {}; [x=1](decltype((x)) y) { decltype((x)) z = x; };};} — _end example_]
7.5.5.3 Qualified names [expr.prim.id.qual]
The component names of a qualified-id are those of its nested-name-specifier and unqualified-id.
A declaration that uses a declarative nested-name-specifiershall be a friend declaration or inhabit a scope that contains the entity being redeclared or specialized.
The nested-name-specifier :: nominates the global namespace.
If a nested-name-specifier Nis declarative and has a simple-template-id with a template argument list Athat involves a template parameter, let T be the template nominated by N without A.
T shall be a class template.
- Otherwise, N nominates the partial specialization ([temp.spec.partial]) of Twhose template argument list is equivalent to A ([temp.over.link]); the program is ill-formed if no such partial specialization exists.
If the nested-name-specifier is not declarative, the entity shall not be a template.
The type of the expression is the type of the result.
The result is an lvalue if the member is
- a function other than a non-static member function,
- a non-static member function if Q is the operand of a unary & operator,
- a variable,
- a structured binding ([dcl.struct.bind]), or
- a data member,
and a prvalue otherwise.
7.5.5.5 Destruction [expr.prim.id.dtor]
An id-expression that denotes the destructor of a type Tnames the destructor of Tif T is a class type ([class.dtor]), otherwise the id-expression is said to name a pseudo-destructor.
[Example 1: struct C { };void f() { C * pc = new C;using C2 = C; pc->C::~C2(); C().C::~C(); using T = int;0 .T::~T(); 0.T::~T(); } — _end example_]