7 Expressions [expr]

7.5 Primary expressions [expr.prim]

7.5.4 Names [expr.prim.id]

id-expression:
	unqualified-id
	qualified-id
An id-expression is a restricted form of a primary-expression.
[Note
: end note
]
An id-expression that denotes a non-static data member or non-static member function of a class can only be used:
  • as part of a class member access in which the object expression refers to the member's class66 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
    :
    struct S {
      int m;
    };
    int i = sizeof(S::m);           // OK
    int j = sizeof(S::m + 42);      // OK
    
    end example
    ]
An id-expression that denotes the specialization of a concept ([temp.concept]) results in a prvalue of type bool.
The expression is true if the concept's normalized constraint-expression is satisfied ([temp.constr.constr]) by the specified template arguments and false otherwise.
[Example
:
template<typename T> concept C = true;
static_assert(C<int>);  // OK
end example
]
[Note
:
A concept's constraints are also considered when using a template name ([temp.names]) and during overload resolution, and they are compared during the the partial ordering of constraints ([temp.constr.order]).
end note
]
A program that refers explicitly or implicitly to a function with a trailing requires-clause whose constraint-expression is not satisfied, other than to declare it, is ill-formed.
[Example
:
void f(int) requires false;

void g() {
  f(0);                         // error: cannot call f
  void (*p1)(int) = f;          // error: cannot take the address of f
  decltype(f)* p2 = nullptr;    // error: the type decltype(f) is invalid
}
In each case, the constraints of f are not satisfied.
In the declaration of p2, those constraints are required to be satisfied even though f is an unevaluated operand.
end example
]
This also applies when the object expression is an implicit (*this) ([class.mfct.non-static]).

7.5.4.1 Unqualified names [expr.prim.id.unqual]

unqualified-id:
	identifier
	operator-function-id
	conversion-function-id
	literal-operator-id
	~ class-name
	~ decltype-specifier
	template-id
An identifier is only an id-expression if it has been suitably declared ([dcl.dcl]) or if it appears as part of a declarator-id.
[Note
:
A class-name or decltype-specifier prefixed by ~ denotes a destructor; see [class.dtor].
Within the definition of a non-static member function, an identifier that names a non-static member is transformed to a class member access expression ([class.mfct.non-static]).
end note
]
The result is the entity denoted by the identifier.
If the entity is a local entity and naming it from outside of an unevaluated operand within the declarative region where the unqualified-id appears would result in some intervening lambda-expression capturing it by copy ([expr.prim.lambda.capture]), 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 closure object of the innermost such intervening lambda-expression.
[Note
:
If that lambda-expression 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.
Otherwise, the type of the expression is the type of the result.
[Note
:
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 lvalue if the entity is a function, variable, structured binding ([dcl.struct.bind]), 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
:
void f() {
  float x, &r = x;
  [=] {
    decltype(x) y1;             // y1 has type float
    decltype((x)) y2 = y1;      // y2 has type float const& because this lambda
                                // is not mutable and x is an lvalue
    decltype(r) r1 = y1;        // r1 has type float&
    decltype((r)) r2 = y2;      // r2 has type float const&
  };
}
end example
]

7.5.4.2 Qualified names [expr.prim.id.qual]

qualified-id:
	nested-name-specifier template unqualified-id
nested-name-specifier:
	::
	type-name ::
	namespace-name ::
	decltype-specifier ::
	nested-name-specifier identifier ::
	nested-name-specifier template simple-template-id ::
The type denoted by a decltype-specifier in a nested-name-specifier shall be a class or enumeration type.
A nested-name-specifier that denotes a class, optionally followed by the keyword template ([temp.names]), and then followed by the name of a member of either that class ([class.mem]) or one of its base classes, is a qualified-id; [class.qual] describes name lookup for class members that appear in qualified-ids.
The result is the member.
The type of the result is the type of the member.
The result is an lvalue if the member is a static member function or a data member and a prvalue otherwise.
[Note
:
A class member can be referred to using a qualified-id at any point in its potential scope ([basic.scope.class]).
end note
]
Where class-name ​::​~ class-name is used, the two class-names shall refer to the same class; this notation names the destructor.
The form ~ decltype-specifier also denotes the destructor, but it shall not be used as the unqualified-id in a qualified-id.
[Note
:
A typedef-name that names a class is a class-name ([class.name]).
end note
]
The nested-name-specifier ​::​ names the global namespace.
A nested-name-specifier that names a namespace, optionally followed by the keyword template ([temp.names]), and then followed by the name of a member of that namespace (or the name of a member of a namespace made visible by a using-directive), is a qualified-id; [namespace.qual] describes name lookup for namespace members that appear in qualified-ids.
The result is the member.
The type of the result is the type of the member.
The result is an lvalue if the member is a function, a variable, or a structured binding ([dcl.struct.bind]) and a prvalue otherwise.
A nested-name-specifier that denotes an enumeration, followed by the name of an enumerator of that enumeration, is a qualified-id that refers to the enumerator.
The result is the enumerator.
The type of the result is the type of the enumeration.
The result is a prvalue.
In a qualified-id, if the unqualified-id is a conversion-function-id, its conversion-type-id shall denote the same type in both the context in which the entire qualified-id occurs and in the context of the class denoted by the nested-name-specifier.