[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.
If this transformation occurs in the predicate of a precondition assertion of a constructor of Xor a postcondition assertion of a destructor of X, the expression is ill-formed.
[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]).
[Example 1: struct C { bool b; C() pre(b) pre(&this->b) pre(sizeof(b) > 0); }; — _end example_]
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 2:
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 3:
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 4: 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 5: 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.
[Note 3:
If E is not declared mutable, the type of such an identifier will typically be const qualified.
— _end note_]
Otherwise, if the unqualified-idnames a coroutine parameter, the type of the expression is that of the copy of the parameter ([dcl.fct.def.coroutine]), and the result is that copy.
Otherwise, if the unqualified-idnames a result binding ([dcl.contract.res]) attached to a function _f_with return type U,
- if U is “reference to T”, then the type of the expression isconst T;
- otherwise, the type of the expression is const U.
Otherwise, if the unqualified-idappears in the predicate of a contract assertion C ([basic.contract]) and the entity is
- a variable declared outside of Cof object type T,
- a variable or template parameter declared outside of Cof type “reference to T”, or
- a structured binding of type Twhose corresponding variable is declared outside of C,
then the type of the expression is const T.
[Example 1: int n = 0;struct X { bool m(); };struct Y { int z = 0;void f(int i, int* p, int& r, X x, X* px) pre (++n) pre (++i) pre (++(*p)) pre (++r) pre (x.m()) pre (px->m()) pre ([=,&i,*this] mutable { ++n; ++i; ++p; ++r; ++this->z; ++z; int j = 17;[&]{ int k = 34;++i; ++j; ++k; }();return true;}());template <int N, int& R, int* P> void g() pre(++N) pre(++R) pre(++(*P)); int h() post(r : ++r) post(r: [=] mutable { ++r; return true;}());int& k() post(r : ++r); }; — _end example_]
Otherwise, 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 ([dcl.struct.bind]), result binding ([dcl.contract.res]), data member, or template parameter object; and a prvalue otherwise ([basic.lval]); it is a bit-field if the identifier designates a bit-field.
If an id-expression Eappears in the predicate of a function contract assertion attached to a function _f_and denotes a function parameter of _f_and the implementation introduces any temporary objects to hold the value of that parameter as specified in [class.temporary],
- if the contract assertion is a precondition assertion and the evaluation of the precondition assertion is sequenced before the initialization of the parameter object,E refers to the most recently initialized such temporary object, and
- if the contract assertion is a postcondition assertion, it is unspecified whether E refers to one of the temporary objects or the parameter object; the choice is consistent within a single evaluation of a postcondition assertion.
If an id-expression Enames a result binding in a postcondition assertion and the implementation introduces any temporary objects to hold the result object as specified in [class.temporary], and the postcondition assertion is sequenced before the initialization of the result object ([expr.call]),E refers to the most recently initialized such temporary object.
[Example 2: 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.
If Q appears in the predicate of a contract assertion C ([basic.contract]) and the entity is
- a variable declared outside of Cof object type T,
- a variable declared outside of Cof type “reference to T”, or
- a structured binding of type Twhose corresponding variable is declared outside of C,
then the type of the expression is const T.
Otherwise, 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_]