|
|
|
10
An lvalue is modifiable unless its type is const-qualified or is a function type.
[Note: A program that
attempts to modify an object through a nonmodifiable lvalue expression or through an rvalue expression is
ill-formed (8.5.18, 8.5.1.6, 8.5.2.2).
— end note ]
11
If a program attempts to access the stored value of an object through a glvalue of other than one of the
following types the behavior is undefined:63
(11.1)
—
the dynamic type of the object,
(11.2)
—
a cv-qualified version of the dynamic type of the object,
(11.3)
—
a type similar (as defined in 7.5) to the dynamic type of the object,
(11.4)
—
a type that is the signed or unsigned type corresponding to the dynamic type of the object,
(11.5)
—
a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type
of the object,
(11.6)
—
an aggregate or union type that includes one of the aforementioned types among its elements or non-
static data members (including, recursively, an element or non-static data member of a subaggregate or
contained union),
(11.7)
—
a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
(11.8)
—
a char, unsigned char, or std::byte type.
8.2.2
Type
[expr.type]
1
If an expression initially has the type “reference to T” (11.3.2, 11.6.3), the type is adjusted to T prior to
any further analysis. The expression designates the object or function denoted by the reference, and the
expression is an lvalue or an xvalue, depending on the expression. [ Note: Before the lifetime of the reference
has started or after it has ended, the behavior is undefined (see 6.6.3).
— end note ]
2
If a prvalue initially has the type “cv T”, where T is a cv-unqualified non-class, non-array type, the type of
the expression is adjusted to T prior to any further analysis.
3
The cv-combined type of two types T1 and T2 is a type T3 similar to T1 whose cv-qualification signature (7.5)
is:
(3.1)
—
for every i > 0, cv3
i istheunionofcvi andcvi;
(3.2)
—
if the resulting cv3
i isdifferentfromcvi orcvi,
then const is added to every cv3
k for0<k<i.
[Note: Given similar types T1 and T2, this construction ensures that both can be converted to T3.
— end
note ]
4
The composite pointer type of two operands p1 and p2 having types T1 and T2, respectively, where at least
one is a pointer or pointer-to-member type or std::nullptr_t, is:
(4.1)
—
if both p1 and p2 are null pointer constants, std::nullptr_t;
(4.2)
—
if either p1 or p2 is a null pointer constant, T2 or T1, respectively;
(4.3)
—
if T1 or T2 is “pointer to cv1 void” and the other type is “pointer to cv2 T”, where T is an object type
or void, “pointer to cv12 void”, where cv12 is the union of cv1 and cv2 ;
(4.4)
—
if T1 or T2 is “pointer to noexcept function” and the other type is “pointer to function”, where the
function types are otherwise the same, “pointer to function”;
(4.5)
—
if T1 is “pointer to cv1 C1” and T2 is “pointer to cv2 C2”, where C1 is reference-related to C2 or C2 is
reference-related to C1 (11.6.3), the cv-combined type of T1 and T2 or the cv-combined type of T2 and
T1, respectively;
(4.6)
—
if T1 is “pointer to member of C1 of type cv1 U1” and T2 is “pointer to member of C2 of type cv2 U2”
where C1 is reference-related to C2 or C2 is reference-related to C1 (11.6.3), the cv-combined type of T2
and T1 or the cv-combined type of T1 and T2, respectively;
(4.7)
—
if T1 and T2 are similar types (7.5), the cv-combined type of T1 and T2;
(4.8)
—
otherwise, a program that necessitates the determination of a composite pointer type is ill-formed.
[ Example:
typedef void *p;
63) The intent of this list is to specify those circumstances in which an object may or may not be aliased.
§ 8.2.2
82
typedef const int *q;
typedef int **pi;
typedef const int **pci;
The composite pointer type of p and q is “pointer to const void”; the composite pointer type of pi and
pci is “pointer to const pointer to const int”.
— end example ]
8.2.3
Context dependence
[expr.context]
1
In some contexts, unevaluated operands appear (8.4.7, 8.5.1.8, 8.5.2.3, 8.5.2.7, 10.1.7.2, Clause 17). An
unevaluated operand is not evaluated. [ Note: In an unevaluated operand, a non-static class member may be
named (8.4) and naming of objects or functions does not, by itself, require that a definition be provided (6.2).
An unevaluated operand is considered a full-expression (6.8.1).
— end note ]
2
In some contexts, an expression only appears for its side effects. Such an expression is called a discarded-value
expression. The array-to-pointer (7.2) and function-to-pointer (7.3) standard conversions are not applied.
The lvalue-to-rvalue conversion (7.1) is applied if and only if the expression is a glvalue of volatile-qualified
type and it is one of the following:
(2.1)
—
( expression ), where expression is one of these expressions,
(2.2)
—
id-expression (8.4.4),
(2.3)
—
subscripting (8.5.1.1),
(2.4)
—
class member access (8.5.1.5),
(2.5)
—
indirection (8.5.2.1),
(2.6)
—
pointer-to-member operation (8.5.4),
(2.7)
—
conditional expression (8.5.16) where both the second and the third operands are one of these expressions,
or
(2.8)
—
comma expression (8.5.19) where the right operand is one of these expressions.
[Note: Using an overloaded operator causes a function call; the above covers only operators with built-in
meaning. — end note ] If the (possibly converted) expression is a prvalue, the temporary materialization
conversion (7.4) is applied. [Note: If the expression is an lvalue of class type, it must have a volatile copy
constructor to initialize the temporary object that is the result object of the lvalue-to-rvalue conversion.
— end note ] The glvalue expression is evaluated and its value is discarded.
8.3
Usual arithmetic conversions
[expr.arith.conv]
1
Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield
result types in a similar way. The purpose is to yield a common type, which is also the type of the result.
This pattern is called the usual arithmetic conversions, which are defined as follows:
(1.1)
—
If either operand is of scoped enumeration type (10.2), no conversions are performed; if the other
operand does not have the same type, the expression is ill-formed.
(1.2)
—
If either operand is of type long double, the other shall be converted to long double.
(1.3)
—
Otherwise, if either operand is double, the other shall be converted to double.
(1.4)
—
Otherwise, if either operand is float, the other shall be converted to float.
(1.5)
—
Otherwise, the integral promotions (7.6) shall be performed on both operands.64 Then the following
rules shall be applied to the promoted operands:
(1.5.1)
—
If both operands have the same type, no further conversion is needed.
(1.5.2)
—
Otherwise, if both operands have signed integer types or both have unsigned integer types, the
operand with the type of lesser integer conversion rank shall be converted to the type of the
operand with greater rank.
(1.5.3)
—
Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the
rank of the type of the other operand, the operand with signed integer type shall be converted to
the type of the operand with unsigned integer type.
64) As a consequence, operands of type bool, char16_t, char32_t, wchar_t, or an enumerated type are converted to some
integral type.
§ 8.3
83
(1.5.4)
—
Otherwise, if the type of the operand with signed integer type can represent all of the values of
the type of the operand with unsigned integer type, the operand with unsigned integer type shall
be converted to the type of the operand with signed integer type.
(1.5.5)
—
Otherwise, both operands shall be converted to the unsigned integer type corresponding to the
type of the operand with signed integer type.
8.4
Primary expressions
[expr.prim]
primary-expression:
literal
this
( expression )
id-expression
lambda-expression
fold-expression
requires-expression
8.4.1
Literals
[expr.prim.literal]
1
A literal is a primary expression. Its type depends on its form (5.13). A string literal is an lvalue; all other
literals are prvalues.
8.4.2
This
[expr.prim.this]
1
The keyword this names a pointer to the object for which a non-static member function (12.2.2.1) is invoked
or a non-static data member’s initializer (12.2) is evaluated.
2
If a declaration declares a member function or member function template of a class X, the expression this
is a prvalue of type “pointer to cv-qualifier-seq X” between the optional cv-qualifier-seq and the end of the
function-definition, member-declarator, or declarator. It shall not appear before the optional cv-qualifier-seq
and it shall not appear within the declaration of a static member function (although its type and value
category are defined within a static member function as they are within a non-static member function).
[ Note: This is because declaration matching does not occur until the complete declarator is known.
— end
note ]
[ Note: In a trailing-return-type, the class being defined is not required to be complete for purposes of
class member access (8.5.1.5). Class members declared later are not visible. [ Example:
struct A {
char g();
template<class T> auto f(T t) -> decltype(t + g())
{ return t + g(); }
};
template auto A::f(int t) -> decltype(t + g());
— end example ]
— end note ]
3
Otherwise, if a member-declarator declares a non-static data member (12.2) of a class X, the expression this
is a prvalue of type “pointer to X” within the optional default member initializer (12.2). It shall not appear
elsewhere in the member-declarator.
4
The expression this shall not appear in any other context. [ Example:
class Outer {
int a[sizeof(*this)];
// error: not inside a member function
unsigned int sz = sizeof(*this);
// OK: in default member initializer
void f() {
int b[sizeof(*this)];
// OK
struct Inner {
int c[sizeof(*this)];
// error: not inside a member function of Inner
};
}
};
— end example ]
§ 8.4.2
84
8.4.3
Parentheses
[expr.prim.paren]
1
A parenthesized expression (E) is a primary expression whose type, value, and value category are identical
to those of E. The parenthesized expression can be used in exactly the same contexts as those where E can be
used, and with the same meaning, except as otherwise indicated.
8.4.4
Names
[expr.prim.id]
id-expression:
unqualified-id
qualified-id
1
An id-expression is a restricted form of a primary-expression. [ Note: An id-expression can appear after .
and -> operators (8.5.1.5).
— end note ]
2
An id-expression that denotes a non-static data member or non-static member function of a class can only
be used:
(2.1)
—
as part of a class member access (8.5.1.5) in which the object expression refers to the member’s class65
or a class derived from that class, or
(2.2)
—
to form a pointer to member (8.5.2.1), or
(2.3)
—
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 ]
3
An id-expression that denotes the specialization of a concept (17.6.8) results in a prvalue of type bool.
The expression is true if the concept’s normalized constraint-expression (17.4.2) is satisfied (17.4.1) 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 (17.2)
and during overload resolution (Clause 16), and they are compared during the the partial ordering of
constraints (17.4.4).
— end note ]
4
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 (8.2).
— end example ]
8.4.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
65) This also applies when the object expression is an implicit (*this) (12.2.2).
§ 8.4.4.1
85
1
An identifier is an id-expression provided it has been suitably declared (Clause 10). [ Note: For operator-
function-ids, see 16.5; for conversion-function-ids, see 15.3.2; for literal-operator-ids, see 16.5.8; for template-
ids, see 17.2. A class-name or decltype-specifier prefixed by ~ denotes a destructor; see 15.4. 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 (12.2.2).
— end note ]
2
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 (8.4.5.2), the type of the expression is the type
of a class member access expression (8.5.1.5) 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 ] Otherwise, the type of the expression is the type of the result. [ Note: The type will be adjusted
as described in 8.2.2 if it is cv-qualified or is a reference type.
— end note ] The expression is an lvalue if the
entity is a function, variable, or data member and a prvalue otherwise (8.2.1); it is a bit-field if the identifier
designates a bit-field (11.5). [ 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 ]
8.4.4.2
Qualified names
[expr.prim.id.qual]
qualified-id:
nested-name-specifier templateopt unqualified-id
nested-name-specifier:
::
type-name ::
namespace-name ::
decltype-specifier ::
nested-name-specifier identifier ::
nested-name-specifier templateopt simple-template-id ::
1
The type denoted by a decltype-specifier in a nested-name-specifier shall be a class or enumeration type.
2
A nested-name-specifier that denotes a class, optionally followed by the keyword template (17.2), and then
followed by the name of a member of either that class (12.2) or one of its base classes (Clause 13), is a
qualified-id; 6.4.3.1 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 (6.3.7).
— end note ] Where class-name ::~ class-name is
used, the two class-names shall refer to the same class; this notation names the destructor (15.4). 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 (12.1).
— end note ]
3
The nested-name-specifier :: names the global namespace. A nested-name-specifier that names a namespace
(10.3), optionally followed by the keyword template (17.2), 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; 6.4.3.2 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
or a variable and a prvalue otherwise.
4
A nested-name-specifier that denotes an enumeration (10.2), 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.
§ 8.4.4.2
86
5
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.
8.4.5
Lambda expressions
[expr.prim.lambda]
lambda-expression:
lambda-introducer compound-statement
lambda-introducer lambda-declarator requires-clauseopt compound-statement
lambda-introducer < template-parameter-list > requires-clauseopt compound-statement
lambda-introducer < template-parameter-list > requires-clauseopt
lambda-declarator requires-clauseopt compound-statement
lambda-introducer:
[ lambda-captureopt ]
lambda-declarator:
( parameter-declaration-clause ) decl-specifier-seqopt
noexcept-specifieropt attribute-specifier-seqopt trailing-return-typeopt
1
Lambda expressions provide a concise way to create simple function objects. [ Example:
#include <algorithm>
#include <cmath>
void abssort(float* x, unsigned N) {
std::sort(x, x + N, [](float a, float b) { return std::abs(a) < std::abs(b); });
}
— end example ]
2
A lambda-expression is a prvalue whose result object is called the closure object. [ Note: A closure object
behaves like a function object (23.14). — end note ]
3
In the decl-specifier-seq of the lambda-declarator, each decl-specifier shall either be mutable or constexpr.
[ Note: The trailing requires-clause is described in Clause 11.
— end note ]
4
If a lambda-expression does not include a lambda-declarator, it is as if the lambda-declarator were (). The
lambda return type is auto, which is replaced by the type specified by the trailing-return-type if provided
and/or deduced from return statements as described in 10.1.7.4. [ Example:
auto x1 = [](int i){ return i; };
// OK: return type is int
auto x2 = []{ return { 1, 2 }; };
// error: deducing return type from braced-init-list
int j;
auto x3 = []()->auto&& { return j; }; // OK: return type is int&
— end example ]
5
A lambda is a generic lambda if the auto type-specifier appears as one of the decl-specifiers in the decl-
specifier-seq of a parameter-declaration of the lambda-expression, or if the lambda has a template-parameter-list.
[ Example:
int i = [](int i, auto a) { return i; }(3, 4);
// OK: a generic lambda
int j = []<class T>(T t, int i) { return i; }(3, 4);
// OK: a generic lambda
— end example ]
8.4.5.1
Closure types
[expr.prim.lambda.closure]
1
The type of a lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union
class type, called the closure type, whose properties are described below.
2
The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the
corresponding lambda-expression. [ Note: This determines the set of namespaces and classes associated with
the closure type (6.4.2). The parameter types of a lambda-declarator do not affect these associated namespaces
and classes.
— end note ] The closure type is not an aggregate type (11.6.1). An implementation may define
the closure type differently from what is described below provided this does not alter the observable behavior
of the program other than by changing:
(2.1)
—
the size and/or alignment of the closure type,
(2.2)
—
whether the closure type is trivially copyable (Clause 12), or
(2.3)
—
whether the closure type is a standard-layout class (Clause 12).
§ 8.4.5.1
87
An implementation shall not add members of rvalue reference type to the closure type.
3
The closure type for a non-generic lambda-expression has a public inline function call operator (16.5.4)
whose parameters and return type are described by the lambda-expression’s parameter-declaration-clause
and trailing-return-type respectively. For a generic lambda, the closure type has a public inline function
call operator member template (17.6.2) whose template-parameter-list consists of the specified template-
parameter-list, if any, to which is appended one invented type template-parameter for each occurrence of auto
in the lambda’s parameter-declaration-clause, in order of appearance. The invented type template-parameter
is a parameter pack if the corresponding parameter-declaration declares a function parameter pack (11.3.5).
The return type and function parameters of the function call operator template are derived from the lambda-
expression’s trailing-return-type and parameter-declaration-clause by replacing each occurrence of auto in the
decl-specifier s of the parameter-declaration-clause with the name of the corresponding invented template-
parameter. The requires-clause of the function call operator template is the requires-clause immediately
following < template-parameter-list >, if any. The trailing requires-clause of the function call operator or
operator template is the requires-clause following the lambda-declarator, if any. [ Example:
auto glambda = [](auto a, auto&& b) { return a < b; };
bool b = glambda(3, 3.14);
// OK
auto vglambda = [](auto printer) {
return [=](auto&& ... ts) {
// OK: ts is a function parameter pack
printer(std::forward<decltype(ts)>(ts)...);
return [=]() {
printer(ts ...);
};
};
};
auto p = vglambda( [](auto v1, auto v2, auto v3)
{ std::cout << v1 << v2 << v3; } );
auto q = p(1, ’a’, 3.14);
// OK: outputs 1a3.14
q();
// OK: outputs 1a3.14
— end example ]
4
The function call operator or operator template is declared const (12.2.2) if and only if the lambda-expression’s
parameter-declaration-clause is not followed by mutable. It is neither virtual nor declared volatile. Any
noexcept-specifier specified on a lambda-expression applies to the corresponding function call operator or
operator template. An attribute-specifier-seq in a lambda-declarator appertains to the type of the corresponding
function call operator or operator template. The function call operator or any given operator template
specialization is a constexpr function if either the corresponding lambda-expression’s parameter-declaration-
clause is followed by constexpr, or it satisfies the requirements for a constexpr function (10.1.5). [Note:
Names referenced in the lambda-declarator are looked up in the context in which the lambda-expression
appears.
— end note ] [ Example:
auto ID = [](auto a) { return a; };
static_assert(ID(3) == 3); // OK
struct NonLiteral {
NonLiteral(int n) : n(n) { }
int n;
};
static_assert(ID(NonLiteral{3}).n == 3); // ill-formed
— end example ]
5
[ Example:
auto monoid = [](auto v) { return [=] { return v; }; };
auto add = [](auto m1) constexpr {
auto ret = m1();
return [=](auto m2) mutable {
auto m1val = m1();
auto plus = [=](auto m2val) mutable constexpr
{ return m1val += m2val; };
ret = plus(m2());
§ 8.4.5.1
88
return monoid(ret);
};
};
constexpr auto zero = monoid(0);
constexpr auto one = monoid(1);
static_assert(add(one)(zero)() == one()); // OK
// Since two below is not declared constexpr, an evaluation of its constexpr member function call operator
// cannot perform an lvalue-to-rvalue conversion on one of its subobjects (that represents its capture)
// in a constant expression.
auto two = monoid(2);
assert(two() == 2); // OK, not a constant expression.
static_assert(add(one)(one)() == two()); // ill-formed: two() is not a constant expression
static_assert(add(one)(one)() == monoid(2)()); // OK
— end example ]
6
The function call operator or operator template may be constrained (17.4.2) by a constrained-parameter (17.1),
a requires-clause (Clause 17), or a trailing requires-clause (Clause 11). [ Example:
template <typename T> concept C1 = /* ... */;
template <std::size_t N> concept C2 = /* ... */;
template <typename A, typename B> concept C3 = /* ... */;
auto f = []<typename T1, C1 T2> requires C2<sizeof(T1) + sizeof(T2)>
(T1 a1, T1 b1, T2 a2, auto a3, auto a4) requires C3<decltype(a4), T2> {
// T2 is a constrained parameter,
// T1 and T2 are constrained by a requires-clause, and
// T2 and the type of a4 are constrained by a trailing requires-clause.
};
— end example ]
7
The closure type for a non-generic lambda-expression with no lambda-capture whose constraints (if any)
are satisfied has a conversion function to pointer to function with C++ language linkage (10.5) having the
same parameter and return types as the closure type’s function call operator. The conversion is to “pointer
to noexcept function” if the function call operator has a non-throwing exception specification. The value
returned by this conversion function is the address of a function F that, when invoked, has the same effect as
invoking the closure type’s function call operator. F is a constexpr function if the function call operator is a
constexpr function. For a generic lambda with no lambda-capture, the closure type has a conversion function
template to pointer to function. The conversion function template has the same invented template parameter
list, and the pointer to function has the same parameter types, as the function call operator template. The
return type of the pointer to function shall behave as if it were a decltype-specifier denoting the return type
of the corresponding function call operator template specialization.
8
[Note: If the generic lambda has no trailing-return-type or the trailing-return-type contains a placeholder
type, return type deduction of the corresponding function call operator template specialization has to be done.
The corresponding specialization is that instantiation of the function call operator template with the same
template arguments as those deduced for the conversion function template. Consider the following:
auto glambda = [](auto a) { return a; };
int (*fp)(int) = glambda;
The behavior of the conversion function of glambda above is like that of the following conversion function:
struct Closure {
template<class T> auto operator()(T t) const { ... }
template<class T> static auto lambda_call_operator_invoker(T a) {
// forwards execution to operator()(a) and therefore has
// the same return type deduced
}
template<class T> using fptr_t =
decltype(lambda_call_operator_invoker(declval<T>())) (*)(T);
§ 8.4.5.1
89
template<class T> operator fptr_t<T>() const
{ return &lambda_call_operator_invoker; }
};
— end note ]
[ Example:
void f1(int (*)(int))
{ }
void f2(char (*)(int))
{ }
void g(int (*)(int))
{ }
// #1
void g(char (*)(char))
{ }
// #2
void h(int (*)(int))
{ }
// #3
void h(char (*)(int))
{ }
// #4
auto glambda = [](auto a) { return a; };
f1(glambda);
// OK
f2(glambda);
// error: ID is not convertible
g(glambda);
// error: ambiguous
h(glambda);
// OK: calls #3 since it is convertible from ID
int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
— end example ]
9
The value returned by any given specialization of this conversion function template is the address of a function
F that, when invoked, has the same effect as invoking the generic lambda’s corresponding function call
operator template specialization. F is a constexpr function if the corresponding specialization is a constexpr
function. [ Note: This will result in the implicit instantiation of the generic lambda’s body. The instantiated
generic lambda’s return type and parameter types shall match the return type and parameter types of the
pointer to function.
— end note ] [ Example:
auto GL = [](auto a) { std::cout << a; return a; };
int (*GL_int)(int) = GL;
// OK: through conversion function template
GL_int(3);
// OK: same as GL(3)
— end example ]
10
The conversion function or conversion function template is public, constexpr, non-virtual, non-explicit, const,
and has a non-throwing exception specification (18.4). [ Example:
auto Fwd = [](int (*fp)(int), auto a) { return fp(a); };
auto C = [](auto a) { return a; };
static_assert(Fwd(C,3) == 3); // OK
// No specialization of the function call operator template can be constexpr (due to the local static).
auto NC = [](auto a) { static int s; return a; };
static_assert(Fwd(NC,3) == 3); // ill-formed
— end example ]
11
The lambda-expression’s compound-statement yields the function-body (11.4) of the function call operator,
but for purposes of name lookup (6.4), determining the type and value of this (12.2.2.1) and transforming id-
expressions referring to non-static class members into class member access expressions using (*this) (12.2.2),
the compound-statement is considered in the context of the lambda-expression. [ Example:
struct S1 {
int x, y;
int operator()(int);
void f() {
[=]()->int {
return operator()(this->x + y); // equivalent to S1::operator()(this->x + (*this).y)
// this has type S1*
};
}
};
§ 8.4.5.1
90
— end example ] Further, a variable __func__ is implicitly defined at the beginning of the compound-statement
of the lambda-expression, with semantics as described in 11.4.1.
12
The closure type associated with a lambda-expression has no default constructor if the lambda-expression has
a lambda-capture and a defaulted default constructor otherwise. It has a defaulted copy constructor and a
defaulted move constructor (15.8). It has a deleted copy assignment operator if the lambda-expression has a
lambda-capture and defaulted copy and move assignment operators otherwise. [ Note: These special member
functions are implicitly defined as usual, and might therefore be defined as deleted.
— end note ]
13
The closure type associated with a lambda-expression has an implicitly-declared destructor (15.4).
14
A member of a closure type shall not be explicitly instantiated (17.8.2), explicitly specialized (17.8.3), or
named in a friend declaration (14.3).
8.4.5.2
Captures
[expr.prim.lambda.capture]
lambda-capture:
capture-default
capture-list
capture-default , capture-list
capture-default:
&
=
capture-list:
capture ...opt
capture-list , capture ...opt
capture:
simple-capture
init-capture
simple-capture:
identifier
& identifier
this
* this
init-capture:
identifier initializer
& identifier initializer
1
The body of a lambda-expression may refer to variables with automatic storage duration and the *this
object (if any) of enclosing block scopes by capturing those entities, as described below.
2
If a lambda-capture includes a capture-default that is &, no identifier in a simple-capture of that lambda-capture
shall be preceded by &. If a lambda-capture includes a capture-default that is =, each simple-capture of
that lambda-capture shall be of the form “& identifier”, “this”, or “* this”. [Note: The form [&,this]
is redundant but accepted for compatibility with ISO C++ 2014.
— end note ] Ignoring appearances in
initializers of init-captures, an identifier or this shall not appear more than once in a lambda-capture.
[ Example:
struct S2 { void f(int i); };
void S2::f(int i) {
[&, i]{ };
// OK
[&, this, i]{ };
// OK, equivalent to [&, i]
[&, &i]{ };
// error: i preceded by & when & is the default
[=, *this]{ };
// OK
[=, this]{ };
// OK, equivalent to [=]
[i, i]{ };
// error: i repeated
[this, *this]{ }; // error: this appears twice
}
— end example ]
3
A lambda-expression is a local lambda expression if its innermost enclosing scope is a block scope (6.3.3),
or if it appears within a default member initializer and its innermost enclosing scope is the corresponding
class scope (6.3.7); any other lambda-expression shall not have a capture-default or simple-capture in its
lambda-introducer.
§ 8.4.5.2
91
4
The identifier in a simple-capture is looked up using the usual rules for unqualified name lookup (6.4.1); each
such lookup shall find a local entity. The simple-captures this and * this denote the local entity *this.
An entity that is designated by a simple-capture is said to be explicitly captured.
5
If an identifier in a simple-capture appears as the declarator-id of a parameter of the lambda-declarator’s
parameter-declaration-clause, the program is ill-formed. [ Example:
void f() {
int x = 0;
auto g = [x](int x) { return 0; }
// error: parameter and simple-capture have the same name
}
— end example ]
6
An init-capture behaves as if it declares and explicitly captures a variable of the form “auto init-capture ;”
whose declarative region is the lambda-expression’s compound-statement, except that:
—
(6.1)
if the capture is by copy (see below), the non-static data member declared for the capture and the
variable are treated as two different ways of referring to the same object, which has the lifetime of the
non-static data member, and no additional copy and destruction is performed, and
(6.2)
—
if the capture is by reference, the variable’s lifetime ends when the closure object’s lifetime ends.
[ Note: This enables an init-capture like “x = std::move(x)”; the second “x” must bind to a declaration in
the surrounding context.
— end note ] [ Example:
int x = 4;
auto y = [&r = x, x = x+1]()->int {
r += 2;
return x+2;
}();
// Updates ::x to 6, and initializes y to 7.
auto z = [a = 42](int a) { return 1; } // error: parameter and local variable have the same name
— end example ]
7
For the purposes of lambda capture, an expression potentially references local entities as follows:
—
(7.1)
An id-expression that names a local entity potentially references that entity; an id-expression that
names one or more non-static class members and does not form a pointer to member (8.5.2.1) potentially
references *this. [Note: This occurs even if overload resolution selects a static member function for
the id-expression.
— end note ]
(7.2)
—
A this expression potentially references *this.
(7.3)
—
A lambda-expression potentially references the local entities named by its simple-captures.
If an expression potentially references a local entity within a declarative region in which it is odr-usable, and
the expression would be potentially evaluated if the effect of any enclosing typeid expressions (8.5.1.8) were
ignored, the entity is said to be implicitly captured by each intervening lambda-expression with an associated
capture-default that does not explicitly capture it. [ Example:
void f(int, const int (&)[2] = {});
// #1
void f(const int&, const int (&)[1]);
// #2
void test() {
const int x = 17;
auto g = [](auto a) {
f(x);
// OK: calls #1, does not capture x
};
auto g1 = [=](auto a) {
f(x);
// OK: calls #1, captures x
};
auto g2 = [=](auto a) {
int selector[sizeof(a) == 1 ? 1 : 2]{};
f(x, selector);
// OK: captures x, might call #1 or #2
};
auto g3 = [=](auto a) {
typeid(a + x);
// captures x regardless of whether a + x is an unevaluated operand
§ 8.4.5.2
92
};
}
Within g1, an implementation might optimize away the capture of x as it is not odr-used.
— end example ]
[Note: The set of captured entities is determined syntactically, and entities might be implicitly captured
even if the expression denoting a local entity is within a discarded statement (9.4.1). [ Example:
template<bool B>
void f(int n) {
[=](auto a) {
if constexpr (B && sizeof(a) > 4) {
(void)n;
// captures n regardless of the value of B and sizeof(int)
}
}(0);
}
— end example ]
— end note ]
8
An entity is captured if it is captured explicitly or implicitly. An entity captured by a lambda-expression
is odr-used (6.2) in the scope containing the lambda-expression. If a lambda-expression explicitly captures
an entity that is not odr-usable or captures a structured binding (explicitly or implicitly), the program is
ill-formed. [ Example:
void f1(int i) {
int const N = 20;
auto m1 = [=]{
int const M = 30;
auto m2 = [i]{
int x[N][M];
// OK: N and M are not odr-used
x[0][0] = i;
// OK: i is explicitly captured by m2 and implicitly captured by m1
};
};
struct s1 {
int f;
void work(int n) {
int m = n*n;
int j = 40;
auto m3 = [this,m] {
auto m4 = [&,j] {
// error: j not odr-usable due to intervening lambda m3
int x = n;
// error: n is odr-used but not odr-usable due to intervening lambda m3
x += m;
// OK: m implicitly captured by m4 and explicitly captured by m3
x += i;
// error: i is odr-used but not odr-usable
// due to intervening function and class scopes
x += f;
// OK: this captured implicitly by m4 and explicitly by m3
};
};
}
};
}
struct s2 {
double ohseven = .007;
auto f() {
return [this] {
return [*this] {
return ohseven;
// OK
}
}();
}
auto g() {
return [] {
return [*this] { };
// error: *this not captured by outer lambda-expression
}();
}
};
— end example ]
§ 8.4.5.2
93
9
A lambda-expression appearing in a default argument shall not implicitly or explicitly capture any entity.
[ Example:
void f2() {
int i = 1;
void g1(int = ([i]{ return i; })());
// ill-formed
void g2(int = ([i]{ return 0; })());
// ill-formed
void g3(int = ([=]{ return i; })());
// ill-formed
void g4(int = ([=]{ return 0; })());
// OK
void g5(int = ([]{ return sizeof i; })());
// OK
}
— end example ]
10
An entity is captured by copy if
(10.1)
—
it is implicitly captured, the capture-default is =, and the captured entity is not *this, or
(10.2)
—
it is explicitly captured with a capture that is not of the form this, & identifier, or & identifier initializer.
For each entity captured by copy, an unnamed non-static data member is declared in the closure type. The
declaration order of these members is unspecified. The type of such a data member is the referenced type
if the entity is a reference to an object, an lvalue reference to the referenced function type if the entity
is a reference to a function, or the type of the corresponding captured entity otherwise. A member of an
anonymous union shall not be captured by copy.
11
Every id-expression within the compound-statement of a lambda-expression that is an odr-use (6.2) of an
entity captured by copy is transformed into an access to the corresponding unnamed data member of the
closure type. [ Note: An id-expression that is not an odr-use refers to the original entity, never to a member
of the closure type. However, such an id-expression can still cause the implicit capture of the entity.
— end
note ] If *this is captured by copy, each expression that odr-uses *this is transformed to instead refer to
the corresponding unnamed data member of the closure type. [ Example:
void f(const int*);
void g() {
const int N = 10;
[=] {
int arr[N];
// OK: not an odr-use, refers to automatic variable
f(&N);
// OK: causes N to be captured; &N points to
// the corresponding member of the closure type
};
}
— end example ]
12
An entity is captured by reference if it is implicitly or explicitly captured but not captured by copy. It is
unspecified whether additional unnamed non-static data members are declared in the closure type for entities
captured by reference. If declared, such non-static data members shall be of literal type. [ Example:
// The inner closure type must be a literal type regardless of how reference captures are represented.
static_assert([](int n) { return [&n] { return ++n; }(); }(3) == 4);
— end example ] A bit-field or a member of an anonymous union shall not be captured by reference.
13
An id-expression within the compound-statement of a lambda-expression that is an odr-use of a reference
captured by reference refers to the entity to which the captured reference is bound and not to the captured
reference.
[Note: The validity of such captures is determined by the lifetime of the object to which the
reference refers, not by the lifetime of the reference itself.
— end note ] [ Example:
auto h(int &r) {
return [&] {
++r;
// Valid after h returns if the lifetime of the
// object to which r is bound has not ended
};
}
— end example ]
14
If a lambda-expression m2 captures an entity and that entity is captured by an immediately enclosing
lambda-expression m1, then m2’s capture is transformed as follows:
§ 8.4.5.2
94
(14.1)
—
if m1 captures the entity by copy, m2 captures the corresponding non-static data member of m1’s closure
type;
(14.2)
—
if m1 captures the entity by reference, m2 captures the same entity captured by m1.
[ Example: The nested lambda expressions and invocations below will output 123234.
int a = 1, b = 1, c = 1;
auto m1 = [a, &b, &c]() mutable {
auto m2 = [a, b, &c]() mutable {
std::cout << a << b << c;
a = 4; b = 4; c = 4;
};
a = 3; b = 3; c = 3;
m2();
};
a = 2; b = 2; c = 2;
m1();
std::cout << a << b << c;
— end example ]
15
When the lambda-expression is evaluated, the entities that are captured by copy are used to direct-initialize
each corresponding non-static data member of the resulting closure object, and the non-static data members
corresponding to the init-captures are initialized as indicated by the corresponding initializer (which may be
copy- or direct-initialization).
(For array members, the array elements are direct-initialized in increasing
subscript order.) These initializations are performed in the (unspecified) order in which the non-static data
members are declared.
[Note: This ensures that the destructions will occur in the reverse order of the
constructions.
— end note ]
16
[Note: If a non-reference entity is implicitly or explicitly captured by reference, invoking the function call
operator of the corresponding lambda-expression after the lifetime of the entity has ended is likely to result
in undefined behavior.
— end note ]
17
A simple-capture followed by an ellipsis is a pack expansion (17.6.3). An init-capture followed by an ellipsis is
ill-formed. [ Example:
template<class... Args>
void f(Args... args) {
auto lm = [&, args...] { return g(args...); };
lm();
}
— end example ]
8.4.6
Fold expressions
[expr.prim.fold]
1
A fold expression performs a fold of a template parameter pack (17.6.3) over a binary operator.
fold-expression:
( cast-expression fold-operator ... )
( ... fold-operator cast-expression )
( cast-expression fold-operator ... fold-operator cast-expression )
fold-operator: one of
+
-
/
%
^ &
|
<<
>>
+=
-=
*=
/=
%=
^= &=
|=
<<=
>>=
=
==
!=
<
>
<=
>= &&
||
,
.*
->*
2
An expression of the form (... op e) where op is a fold-operator is called a unary left fold. An expression of
the form (e op ...) where op is a fold-operator is called a unary right fold. Unary left folds and unary right
folds are collectively called unary folds. In a unary fold, the cast-expression shall contain an unexpanded
parameter pack (17.6.3).
3
An expression of the form (e1 op1 ... op2 e2) where op1 and op2 are fold-operator s is called a binary fold.
In a binary fold, op1 and op2 shall be the same fold-operator, and either e1 shall contain an unexpanded
parameter pack or e2 shall contain an unexpanded parameter pack, but not both. If e2 contains an
unexpanded parameter pack, the expression is called a binary left fold. If e1 contains an unexpanded
parameter pack, the expression is called a binary right fold. [ Example:
§ 8.4.6
95
template<typename ...Args>
bool f(Args ...args) {
return (true && ... && args); // OK
}
template<typename ...Args>
bool f(Args ...args) {
return (args + ... + args);
// error: both operands contain unexpanded parameter packs
}
— end example ]
8.4.7
Requires expressions
[expr.prim.req]
1
A requires-expression provides a concise way to express requirements on template arguments that can be
checked by name lookup (6.4) or by checking properties of types and expressions.
requires-expression:
requires requirement-parameter-listopt requirement-body
requirement-parameter-list:
( parameter-declaration-clauseopt )
requirement-body:
{ requirement-seq }
requirement-seq:
requirement
requirement-seq requirement
requirement:
simple-requirement
type-requirement
compound-requirement
nested-requirement
2
A requires-expression is a prvalue of type bool whose value is described below. Expressions appearing within
a requirement-body are unevaluated operands (8.2).
3
[Example: A common use of requires-expressions is to define requirements in concepts such as the one
below:
template<typename T>
concept R = requires (T i) {
typename T::type;
{*i} -> const typename T::type&;
};
A requires-expression can also be used in a requires-clause (Clause 17) as a way of writing ad hoc constraints
on template arguments such as the one below:
template<typename T>
requires requires (T x) { x + x; }
T add(T a, T b) { return a + b; }
The first requires introduces the requires-clause, and the second introduces the requires-expression.
— end
example ]
4
A requires-expression may introduce local parameters using a parameter-declaration-clause (11.3.5). A local
parameter of a requires-expression shall not have a default argument. Each name introduced by a local
parameter is in scope from the point of its declaration until the closing brace of the requirement-body. These
parameters have no linkage, storage, or lifetime; they are only used as notation for the purpose of defining
requirements. The parameter-declaration-clause of a requirement-parameter-list shall not terminate with an
ellipsis.
[ Example:
template<typename T>
concept C = requires(T t, ...) {
// error: terminates with an ellipsis
t;
};
— end example ]
§ 8.4.7
96
5
The requirement-body contains a sequence of requirements. These requirements may refer to local parameters,
template parameters, and any other declarations visible from the enclosing context.
6
The substitution of template arguments into a requires-expression may result in the formation of invalid
types or expressions in its requirements or the violation of the semantic constraints of those requirements.
In such cases, the requires-expression evaluates to false; it does not cause the program to be ill-formed.
The substitution and semantic constraint checking proceeds in lexical order and stops when a condition that
determines the result of the requires-expression is encountered. If substitution (if any) and semantic constraint
checking succeed, the requires-expression evaluates to true. [ Note: If a requires-expression contains invalid
types or expressions in its requirements, and it does not appear within the declaration of a templated entity,
then the program is ill-formed.
— end note ] If the substitution of template arguments into a requirement
would always result in a substitution failure, the program is ill-formed; no diagnostic required. [ Example:
template<typename T> concept C =
requires {
new int[-(int)sizeof(T)]; // ill-formed, no diagnostic required
};
— end example ]
8.4.7.1
Simple requirements
[expr.prim.req.simple]
simple-requirement:
expression ;
1
A simple-requirement asserts the validity of an expression. [Note: The enclosing requires-expression will
evaluate to false if substitution of template arguments into the expression fails. The expression is an
unevaluated operand (8.2).
— end note ] [ Example:
template<typename T> concept C =
requires (T a, T b) {
a + b;
// C<T> is true if a + b is a valid expression
};
— end example ]
8.4.7.2
Type requirements
[expr.prim.req.type]
type-requirement:
typename nested-name-specifieropt type-name ;
1
A type-requirement asserts the validity of a type. [ Note: The enclosing requires-expression will evaluate to
false if substitution of template arguments fails.
— end note ] [ Example:
template<typename T, typename T::type = 0> struct S;
template<typename T> using Ref = T&;
template<typename T> concept C = requires {
typename T::inner;
// required nested member name
typename S<T>;
// required class template specialization
typename Ref<T>;
// required alias template substitution, fails if T is void
};
— end example ]
2
A type-requirement that names a class template specialization does not require that type to be complete (6.7).
8.4.7.3
Compound requirements
[expr.prim.req.compound]
compound-requirement:
{ expression } noexceptopt return-type-requirementopt ;
return-type-requirement:
trailing-return-type
-> cv-qualifier-seqopt constrained-parameter cv-qualifier-seqopt abstract-declaratoropt
1
A compound-requirement asserts properties of the expression E. Substitution of template arguments (if any)
and verification of semantic properties proceed in the following order:
(1.1)
—
Substitution of template arguments (if any) into the expression is performed.
(1.2)
—
If the noexcept specifier is present, E shall not be a potentially-throwing expression (18.4).
§ 8.4.7.3
97
(1.3)
—
If the return-type-requirement is present, then:
(1.3.1)
—
Substitution of template arguments (if any) into the return-type-requirement is performed.
(1.3.2)
—
If the return-type-requirement is a trailing-return-type, E is implicitly convertible to the type named
by the trailing-return-type. If conversion fails, the enclosing requires-expression is false.
—
(1.3.3)
If the return-type-requirement starts with a constrained-parameter (17.1), the expression is deduced
against an invented function template F using the rules in 17.9.2.1. F is a void function template
with a single type template parameter T declared with the constrained-parameter. A cv-qualifier-seq
cv is formed as the union of const and volatile specifiers around the constrained-parameter. F
has a single parameter whose type-specifier is cv T followed by the abstract-declarator. If deduction
fails, the enclosing requires-expression is false.
[ Example:
template<typename T> concept C1 = requires(T x) {
{x++};
};
The compound-requirement in C1 requires that x++ is a valid expression. It is equivalent to the simple-
requirement x++;.
template<typename T> concept C2 = requires(T x) {
{*x} -> typename T::inner;
};
The compound-requirement in C2 requires that *x is a valid expression, that typename T::inner is a valid
type, and that *x is implicitly convertible to typename T::inner.
template<typename T, typename U> concept C3 = requires (T t, U u) {
t == u;
};
template<typename T> concept C4 = requires(T x) {
{*x} -> C3<int> const&;
};
The compound-requirement requires that *x be deduced as an argument for the invented function:
template<C3<int> X> void f(X const&);
In this case, deduction only succeeds if an expression of the type deduced for X can be compared to an int
with the == operator.
template<typename T> concept C5 =
requires(T x) {
{g(x)} noexcept;
};
The compound-requirement in C5 requires that g(x) is a valid expression and that g(x) is non-throwing.
— end example ]
8.4.7.4
Nested requirements
[expr.prim.req.nested]
nested-requirement:
requires constraint-expression ;
1
A nested-requirement can be used to specify additional constraints in terms of local parameters. The
constraint-expression shall be satisfied (17.4.2) by the substituted template arguments, if any. Substitution of
template arguments into a nested-requirement does not result in substitution into the constraint-expression
other than as specified in 17.4.2. [ Example:
template<typename U> concept C = sizeof(U) == 1;
template<typename T> concept D = requires (T t) {
requires C<decltype (+t)>;
};
D<T> is satisfied if sizeof(decltype (+t)) == 1 (17.4.1.2).
— end example ]
2
A local parameter shall only appear as an unevaluated operand (8.2) within the constraint-expression.
[ Example:
§ 8.4.7.4
98
template<typename T> concept C = requires (T a) {
requires sizeof(a) == 4;
// OK
requires a == 0;
// error: evaluation of a constraint variable
}
— end example ]
8.5
Compound expressions
[expr.compound]
8.5.1
Postfix expressions
[expr.post]
1
Postfix expressions group left-to-right.
postfix-expression:
primary-expression
postfix-expression [ expr-or-braced-init-list ]
postfix-expression ( expression-listopt )
simple-type-specifier ( expression-listopt )
typename-specifier ( expression-listopt )
simple-type-specifier braced-init-list
typename-specifier braced-init-list
postfix-expression . templateopt id-expression
postfix-expression -> templateopt id-expression
postfix-expression . pseudo-destructor-name
postfix-expression -> pseudo-destructor-name
postfix-expression ++
postfix-expression --
dynamic_cast < type-id > ( expression )
static_cast < type-id > ( expression )
reinterpret_cast < type-id > ( expression )
const_cast < type-id > ( expression )
typeid ( expression )
typeid ( type-id )
expression-list:
initializer-list
pseudo-destructor-name:
nested-name-specifieropt type-name :: ~ type-name
nested-name-specifier template simple-template-id :: ~ type-name
~ type-name
~ decltype-specifier
2
[ Note: The > token following the type-id in a dynamic_cast, static_cast, reinterpret_cast, or const_-
cast may be the product of replacing a >> token by two consecutive > tokens (17.2). — end note ]
8.5.1.1
Subscripting
[expr.sub]
1
A postfix expression followed by an expression in square brackets is a postfix expression. One of the expressions
shall be a glvalue of type “array of T” or a prvalue of type “pointer to T” and the other shall be a prvalue of
unscoped enumeration or integral type. The result is of type “T”. The type “T” shall be a completely-defined
object type.66 The expression E1[E2] is identical (by definition) to *((E1)+(E2)) [ Note: see 8.5.2 and 8.5.6
for details of * and + and 11.3.4 for details of arrays.
— end note ] , except that in the case of an array
operand, the result is an lvalue if that operand is an lvalue and an xvalue otherwise. The expression E1 is
sequenced before the expression E2.
2
A braced-init-list shall not be used with the built-in subscript operator.
8.5.1.2
Function call
[expr.call]
1
A function call is a postfix expression followed by parentheses containing a possibly empty, comma-separated
list of initializer-clauses which constitute the arguments to the function. The postfix expression shall have
function type or function pointer type. For a call to a non-member function or to a static member function,
the postfix expression shall be either an lvalue that refers to a function (in which case the function-to-pointer
standard conversion (7.3) is suppressed on the postfix expression), or it shall have function pointer type.
Calling a function through an expression whose function type is different from the function type of the
called function’s definition results in undefined behavior (10.5). For a call to a non-static member function,
66) This is true even if the subscript operator is used in the following common idiom: &x[0].
§ 8.5.1.2
99
the postfix expression shall be an implicit (12.2.2, 12.2.3) or explicit class member access (8.5.1.5) whose
id-expression is a function member name, or a pointer-to-member expression (8.5.4) selecting a function
member; the call is as a member of the class object referred to by the object expression. In the case of an
implicit class member access, the implied object is the one pointed to by this. [ Note: A member function
call of the form f() is interpreted as (*this).f() (see 12.2.2).
— end note ] If a function or member
function name is used, the name can be overloaded (Clause 16), in which case the appropriate function shall
be selected according to the rules in 16.3. If the selected function is non-virtual, or if the id-expression in the
class member access expression is a qualified-id, that function is called. Otherwise, its final overrider (13.3)
in the dynamic type of the object expression is called; such a call is referred to as a virtual function call.
[ Note: The dynamic type is the type of the object referred to by the current value of the object expression.
15.7 describes the behavior of virtual function calls when the object expression refers to an object under
construction or destruction.
— end note ]
2
[ Note: If a function or member function name is used, and name lookup (6.4) does not find a declaration of
that name, the program is ill-formed. No function is implicitly declared by such a call.
— end note ]
3
If the postfix-expression designates a destructor (15.4), the type of the function call expression is void;
otherwise, the type of the function call expression is the return type of the statically chosen function (i.e.,
ignoring the virtual keyword), even if the type of the function actually called is different. This return type
shall be an object type, a reference type or cv void.
4
When a function is called, each parameter (11.3.5) shall be initialized (11.6, 15.8, 15.1) with its corresponding
argument. If the function is a non-static member function, the this parameter of the function (12.2.2.1) shall
be initialized with a pointer to the object of the call, converted as if by an explicit type conversion (8.5.3).
[ Note: There is no access or ambiguity checking on this conversion; the access checking and disambiguation
are done as part of the (possibly implicit) class member access operator. See 13.2, 14.2, and 8.5.1.5.
— end
note ] When a function is called, the parameters that have object type shall have completely-defined object
type. [ Note: this still allows a parameter to be a pointer or reference to an incomplete class type. However,
it prevents a passed-by-value parameter to have an incomplete class type.
— end note ] It is implementation-
defined whether the lifetime of a parameter ends when the function in which it is defined returns or at the
end of the enclosing full-expression. The initialization and destruction of each parameter occurs within the
context of the calling function. [ Example: The access of the constructor, conversion functions or destructor
is checked at the point of call in the calling function. If a constructor or destructor for a function parameter
throws an exception, the search for a handler starts in the scope of the calling function; in particular, if the
function called has a function-try-block (Clause 18) with a handler that could handle the exception, this
handler is not considered.
— end example ]
5
The postfix-expression is sequenced before each expression in the expression-list and any default argument. The
initialization of a parameter, including every associated value computation and side effect, is indeterminately
sequenced with respect to that of any other parameter. [ Note: All side effects of argument evaluations are
sequenced before the function is entered (see 6.8.1).
— end note ] [ Example:
void f() {
std::string s = "but I have heard it works even if you don’t believe in it";
s.replace(0, 4, "").replace(s.find("even"), 4, "only").replace(s.find(" don’t"), 6, "");
assert(s == "I have heard it works only if you believe in it"); // OK
}
— end example ] [ Note: If an operator function is invoked using operator notation, argument evaluation is
sequenced as specified for the built-in operator; see 16.3.1.2.
— end note ] [ Example:
struct S {
S(int);
};
int operator<<(S, int);
int i, j;
int x = S(i=1) << (i=2);
int y = operator<<(S(j=1), j=2);
After performing the initializations, the value of i is 2 (see 8.5.7), but it is unspecified whether the value of j
is 1 or 2.
— end example ]
6
The result of a function call is the result of the operand of the evaluated return statement (9.6.3) in the
called function (if any), except in a virtual function call if the return type of the final overrider is different
§ 8.5.1.2
100
from the return type of the statically chosen function, the value returned from the final overrider is converted
to the return type of the statically chosen function.
7
[Note: A function can change the values of its non-const parameters, but these changes cannot affect the
values of the arguments except where a parameter is of a reference type (11.3.2); if the reference is to
a const-qualified type, const_cast is required to be used to cast away the constness in order to modify
the argument’s value. Where a parameter is of const reference type a temporary object is introduced if
needed (10.1.7, 5.13, 5.13.5, 11.3.4, 15.2). In addition, it is possible to modify the values of non-constant
objects through pointer parameters.
— end note ]
8
A function can be declared to accept fewer arguments (by declaring default arguments (11.3.6)) or more
arguments (by using the ellipsis, ..., or a function parameter pack (11.3.5)) than the number of parameters
in the function definition (11.4).
[Note: This implies that, except where the ellipsis (...) or a function
parameter pack is used, a parameter is available for each argument.
— end note ]
9
When there is no parameter for a given argument, the argument is passed in such a way that the receiving
function can obtain the value of the argument by invoking va_arg (21.11). [ Note: This paragraph does not
apply to arguments passed to a function parameter pack. Function parameter packs are expanded during
template instantiation (17.6.3), thus each such argument has a corresponding parameter when a function
template specialization is actually called.
— end note ] The lvalue-to-rvalue (7.1), array-to-pointer (7.2), and
function-to-pointer (7.3) standard conversions are performed on the argument expression. An argument that
has type cv std::nullptr_t is converted to type void* (7.11). After these conversions, if the argument does
not have arithmetic, enumeration, pointer, pointer-to-member, or class type, the program is ill-formed. Passing
a potentially-evaluated argument of class type (Clause 12) having a non-trivial copy constructor, a non-trivial
move constructor, or a non-trivial destructor, with no corresponding parameter, is conditionally-supported
with implementation-defined semantics. If the argument has integral or enumeration type that is subject to
the integral promotions (7.6), or a floating-point type that is subject to the floating-point promotion (7.7),
the value of the argument is converted to the promoted type before the call. These promotions are referred
to as the default argument promotions.
10
Recursive calls are permitted, except to the main function (6.8.3.1).
11
A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function
type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.
8.5.1.3
Explicit type conversion (functional notation)
[expr.type.conv]
1
A simple-type-specifier (10.1.7.2) or typename-specifier (17.7) followed by a parenthesized optional expression-
list or by a braced-init-list (the initializer) constructs a value of the specified type given the initializer. If the
type is a placeholder for a deduced class type, it is replaced by the return type of the function selected by
overload resolution for class template deduction (16.3.1.8) for the remainder of this subclause.
2
If the initializer is a parenthesized single expression, the type conversion expression is equivalent to the
corresponding cast expression (8.5.3). Otherwise, if the type is cv void and the initializer is (), the expression
is a prvalue of the specified type that performs no initialization. Otherwise, the expression is a prvalue of the
specified type whose result object is direct-initialized (11.6) with the initializer. For an expression of the
form T(), T shall not be an array type.
8.5.1.4
Pseudo destructor call
[expr.pseudo]
1
The use of a pseudo-destructor-name after a dot . or arrow -> operator represents the destructor for the
non-class type denoted by type-name or decltype-specifier. The result shall only be used as the operand for
the function call operator (), and the result of such a call has type void. The only effect is the evaluation of
the postfix-expression before the dot or arrow.
2
The left-hand side of the dot operator shall be of scalar type. The left-hand side of the arrow operator shall
be of pointer to scalar type. This scalar type is the object type. The cv-unqualified versions of the object
type and of the type designated by the pseudo-destructor-name shall be the same type. Furthermore, the
two type-names in a pseudo-destructor-name of the form
nested-name-specifieropt type-name :: ~ type-name
shall designate the same scalar type (ignoring cv-qualification).
8.5.1.5
Class member access
[expr.ref]
1
A postfix expression followed by a dot . or an arrow ->, optionally followed by the keyword template (17.2),
and then followed by an id-expression, is a postfix expression. The postfix expression before the dot or arrow
§ 8.5.1.5
101
is evaluated;67 the result of that evaluation, together with the id-expression, determines the result of the
entire postfix expression.
2
For the first option (dot) the first expression shall be a glvalue having class type. For the second option
(arrow) the first expression shall be a prvalue having pointer to class type. In both cases, the class type shall
be complete unless the class member access appears in the definition of that class. [Note: If the class is
incomplete, lookup in the complete class type is required to refer to the same declaration (6.3.7).
— end
note ] The expression E1->E2 is converted to the equivalent form (*(E1)).E2; the remainder of 8.5.1.5 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 12), the name
of a class is also considered a nested member of that class.
— end note ] [ Note: 6.4.5 describes how names
are looked up after the . and -> operators.
— end note ]
3
Abbreviating postfix-expression.id-expression as E1.E2, E1 is called the object expression. If E2 is a bit-field,
E1.E2 is a bit-field. The type and value category of E1.E2 are determined as follows. In the remainder
of 8.5.1.5, cq represents either const or the absence of const and vq represents either volatile or the
absence of volatile. cv represents an arbitrary set of cv-qualifiers, as defined in 6.7.3.
4
If E2 is declared to have type “reference to T”, then E1.E2 is an lvalue; the type of E1.E2 is T. Otherwise,
one of the following rules applies.
(4.1)
—
If E2 is a static data member and the type of E2 is T, then E1.E2 is an lvalue; the expression designates
the named member of the class. The type of E1.E2 is T.
—
(4.2)
If E2 is a non-static data member and the type of E1 is “cq1 vq1 X”, and the type of E2 is “cq2 vq2 T”,
the expression designates the named member of the object designated by the first expression. If E1 is
an lvalue, then E1.E2 is an lvalue; otherwise E1.E2 is an xvalue. Let the notation vq12 stand for the
“union” of vq1 and vq2; that is, if vq1 or vq2 is volatile, then vq12 is volatile. Similarly, let the
notation cq12 stand for the “union” of cq1 and cq2 ; that is, if cq1 or cq2 is const, then cq12 is const.
If E2 is declared to be a mutable member, then the type of E1.E2 is “vq12 T”. If E2 is not declared to
be a mutable member, then the type of E1.E2 is “cq12 vq12 T”.
(4.3)
—
If E2 is a (possibly overloaded) member function, function overload resolution (16.3) is used to determine
whether E1.E2 refers to a static or a non-static member function.
(4.3.1)
—
If it refers to a static member function and the type of E2 is “function of parameter-type-list
returning T”, then E1.E2 is an lvalue; the expression designates the static member function. The
type of E1.E2 is the same type as that of E2, namely “function of parameter-type-list returning T”.
(4.3.2)
—
Otherwise, if E1.E2 refers to a non-static member function and the type of E2 is “function of
parameter-type-list cv ref-qualifieropt returning T”, then E1.E2 is a prvalue. The expression
designates a non-static member function. The expression can be used only as the left-hand operand
of a member function call (12.2.1). [Note: Any redundant set of parentheses surrounding the
expression is ignored (8.4).
— end note ] The type of E1.E2 is “function of parameter-type-list cv
returning T”.
(4.4)
—
If E2 is a nested type, the expression E1.E2 is ill-formed.
(4.5)
—
If E2 is a member enumerator and the type of E2 is T, the expression E1.E2 is a prvalue. The type of
E1.E2 is T.
5
If E2 is a non-static data member or a non-static member function, the program is ill-formed if the class of
which E2 is directly a member is an ambiguous base (13.2) of the naming class (14.2) of E2. [ Note: The
program is also ill-formed if the naming class is an ambiguous base of the class type of the object expression;
see 14.2.
— end note ]
8.5.1.6
Increment and decrement
[expr.post.incr]
1
The value of a postfix ++ expression is the value of its operand.
[Note: The value obtained is a copy
of the original value
— end note ] The operand shall be a modifiable lvalue. The type of the operand
shall be an arithmetic type other than cv bool, or a pointer to a complete object type. The value of the
operand object is modified by adding 1 to it. The value computation of the ++ expression is sequenced before
the modification of the operand object. With respect to an indeterminately-sequenced function call, the
67) If the class member access expression is evaluated, the subexpression evaluation happens even if the result is unnecessary to
determine the value of the entire postfix expression, for example if the id-expression denotes a static member.
68) Note that (*(E1)) is an lvalue.
§ 8.5.1.6
102
operation of postfix ++ is a single evaluation. [ Note: Therefore, a function call shall not intervene between
the lvalue-to-rvalue conversion and the side effect associated with any single postfix ++ operator.
— end
note ] The result is a prvalue. The type of the result is the cv-unqualified version of the type of the operand.
If the operand is a bit-field that cannot represent the incremented value, the resulting value of the bit-field is
implementation-defined. See also 8.5.6 and 8.5.18.
2
The operand of postfix -- is decremented analogously to the postfix ++ operator. [ Note: For prefix increment
and decrement, see 8.5.2.2.
— end note ]
8.5.1.7
Dynamic cast
[expr.dynamic.cast]
1
The result of the expression dynamic_cast<T>(v) is the result of converting the expression v to type T. T
shall be a pointer or reference to a complete class type, or “pointer to cv void”. The dynamic_cast operator
shall not cast away constness (8.5.1.11).
2
If T is a pointer type, v shall be a prvalue of a pointer to complete class type, and the result is a prvalue of
type T. If T is an lvalue reference type, v shall be an lvalue of a complete class type, and the result is an
lvalue of the type referred to by T. If T is an rvalue reference type, v shall be a glvalue having a complete
class type, and the result is an xvalue of the type referred to by T.
3
If the type of v is the same as T, or it is the same as T except that the class object type in T is more
cv-qualified than the class object type in v, the result is v (converted if necessary).
4
If the value of v is a null pointer value in the pointer case, the result is the null pointer value of type T.
5
If T is “pointer to cv1 B” and v has type “pointer to cv2 D” such that B is a base class of D, the result is a
pointer to the unique B subobject of the D object pointed to by v. Similarly, if T is “reference to cv1 B” and v
has type cv2 D such that B is a base class of D, the result is the unique B subobject of the D object referred to
by v.69 In both the pointer and reference cases, the program is ill-formed if cv2 has greater cv-qualification
than cv1 or if B is an inaccessible or ambiguous base class of D. [ Example:
struct B { };
struct D : B { };
void foo(D* dp) {
B* bp = dynamic_cast<B*>(dp);
// equivalent to B* bp = dp;
}
— end example ]
6
Otherwise, v shall be a pointer to or a glvalue of a polymorphic type (13.3).
7
If T is “pointer to cv void”, then the result is a pointer to the most derived object pointed to by v. Otherwise,
a runtime check is applied to see if the object pointed or referred to by v can be converted to the type pointed
or referred to by T.
8
If C is the class type to which T points or refers, the runtime check logically executes as follows:
(8.1)
—
If, in the most derived object pointed (referred) to by v, v points (refers) to a public base class subobject
of a C object, and if only one object of type C is derived from the subobject pointed (referred) to by v
the result points (refers) to that C object.
(8.2)
—
Otherwise, if v points (refers) to a public base class subobject of the most derived object, and the type
of the most derived object has a base class, of type C, that is unambiguous and public, the result points
(refers) to the C subobject of the most derived object.
(8.3)
—
Otherwise, the runtime check fails.
9
The value of a failed cast to pointer type is the null pointer value of the required result type. A failed
cast to reference type throws an exception (18.1) of a type that would match a handler (18.3) of type
std::bad_cast (21.7.3).
[ Example:
class A { virtual void f(); };
class B { virtual void g(); };
class D : public virtual A, private B { };
void g() {
D d;
B* bp = (B*)&d;
// cast needed to break protection
69) The most derived object (6.6.2) pointed or referred to by v can contain other B objects as base classes, but these are ignored.
§ 8.5.1.7
103
A* ap = &d;
// public derivation, no cast needed
D& dr = dynamic_cast<D&>(*bp);
// fails
ap = dynamic_cast<A*>(bp);
// fails
bp = dynamic_cast<B*>(ap);
// fails
ap = dynamic_cast<A*>(&d);
// succeeds
bp = dynamic_cast<B*>(&d);
// ill-formed (not a runtime check)
}
class E : public D, public B { };
class F : public E, public D { };
void h() {
F f;
A* ap
= &f;
// succeeds: finds unique A
D* dp
= dynamic_cast<D*>(ap);
// fails: yields null; f has two D subobjects
E* ep
= (E*)ap;
// ill-formed: cast from virtual base
E* ep1 = dynamic_cast<E*>(ap);
// succeeds
}
— end example ] [ Note: 15.7 describes the behavior of a dynamic_cast applied to an object under construction
or destruction.
— end note ]
8.5.1.8
Type identification
[expr.typeid]
1
The result of a typeid expression is an lvalue of static type const std::type_info (21.7.2) and dynamic type
const std::type_info or const name where name is an implementation-defined class publicly derived from
std::type_info which preserves the behavior described in 21.7.2.70 The lifetime of the object referred to by
the lvalue extends to the end of the program. Whether or not the destructor is called for the std::type_info
object at the end of the program is unspecified.
2
When typeid is applied to a glvalue expression whose type is a polymorphic class type (13.3), the result refers
to a std::type_info object representing the type of the most derived object (6.6.2) (that is, the dynamic
type) to which the glvalue refers. If the glvalue expression is obtained by applying the unary * operator to a
pointer71 and the pointer is a null pointer value (7.11), the typeid expression throws an exception (18.1) of
a type that would match a handler of type std::bad_typeid exception (21.7.4).
3
When typeid is applied to an expression other than a glvalue of a polymorphic class type, the result
refers to a std::type_info object representing the static type of the expression. Lvalue-to-rvalue (7.1),
array-to-pointer (7.2), and function-to-pointer (7.3) conversions are not applied to the expression. If the
expression is a prvalue, the temporary materialization conversion (7.4) is applied. The expression is an
unevaluated operand (8.2).
4
When typeid is applied to a type-id, the result refers to a std::type_info object representing the type of
the type-id. If the type of the type-id is a reference to a possibly cv-qualified type, the result of the typeid
expression refers to a std::type_info object representing the cv-unqualified referenced type. If the type of
the type-id is a class type or a reference to a class type, the class shall be completely-defined.
5
If the type of the expression or type-id is a cv-qualified type, the result of the typeid expression refers to a
std::type_info object representing the cv-unqualified type. [ Example:
class D { /* ... */ };
D d1;
const D d2;
typeid(d1) == typeid(d2);
// yields true
typeid(D)
== typeid(const D);
// yields true
typeid(D)
== typeid(d2);
// yields true
typeid(D)
== typeid(const D&); // yields true
— end example ]
6
If the header <typeinfo> (21.7.2) is not included prior to a use of typeid, the program is ill-formed.
7
[ Note: 15.7 describes the behavior of typeid applied to an object under construction or destruction.
— end
note ]
70) The recommended name for such a class is extended_type_info.
71) If p is an expression of pointer type, then *p, (*p), *(p), ((*p)), *((p)), and so on all meet this requirement.
§ 8.5.1.8
104
8.5.1.9
Static cast
[expr.static.cast]
1
The result of the expression static_cast<T>(v) is the result of converting the expression v to type T. If T
is an lvalue reference type or an rvalue reference to function type, the result is an lvalue; if T is an rvalue
reference to object type, the result is an xvalue; otherwise, the result is a prvalue. The static_cast operator
shall not cast away constness (8.5.1.11).
2
An lvalue of type “cv1 B”, where B is a class type, can be cast to type “reference to cv2 D”, where D is a class
derived (Clause 13) from B, if cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. If B is
a virtual base class of D or a base class of a virtual base class of D, or if no valid standard conversion from
“pointer to D” to “pointer to B” exists (7.11), the program is ill-formed. An xvalue of type “cv1 B” can be cast
to type “rvalue reference to cv2 D” with the same constraints as for an lvalue of type “cv1 B”. If the object of
type “cv1 B” is actually a base class subobject of an object of type D, the result refers to the enclosing object
of type D. Otherwise, the behavior is undefined. [ Example:
struct B { };
struct D : public B { };
D d;
B &br = d;
static_cast<D&>(br);
// produces lvalue to the original d object
— end example ]
3
An lvalue of type “cv1 T1” can be cast to type “rvalue reference to cv2 T2” if “cv2 T2” is reference-compatible
with “cv1 T1” (11.6.3). If the value is not a bit-field, the result refers to the object or the specified base
class subobject thereof; otherwise, the lvalue-to-rvalue conversion (7.1) is applied to the bit-field and the
resulting prvalue is used as the expression of the static_cast for the remainder of this subclause. If T2 is
an inaccessible (Clause 14) or ambiguous (13.2) base class of T1, a program that necessitates such a cast is
ill-formed.
4
An expression e can be explicitly converted to a type T if there is an implicit conversion sequence (16.3.3.1)
from e to T, or if overload resolution for a direct-initialization (11.6) of an object or reference of type T from
e would find at least one viable function (16.3.2). If T is a reference type, the effect is the same as performing
the declaration and initialization
T t(e);
for some invented temporary variable t (11.6) and then using the temporary variable as the result of the
conversion. Otherwise, the result object is direct-initialized from e. [ Note: The conversion is ill-formed when
attempting to convert an expression of class type to an inaccessible or ambiguous base class.
— end note ]
5
Otherwise, the static_cast shall perform one of the conversions listed below. No other conversion shall be
performed explicitly using a static_cast.
6
Any expression can be explicitly converted to type cv void, in which case it becomes a discarded-value
expression (8.2). [ Note: However, if the value is in a temporary object (15.2), the destructor for that object
is not executed until the usual time, and the value of the object is preserved for the purpose of executing the
destructor.
— end note ]
7
The inverse of any standard conversion sequence (Clause 7) not containing an lvalue-to-rvalue (7.1), array-to-
pointer (7.2), function-to-pointer (7.3), null pointer (7.11), null member pointer (7.12), boolean (7.14), or
function pointer (7.13) conversion, can be performed explicitly using static_cast. A program is ill-formed
if it uses static_cast to perform the inverse of an ill-formed standard conversion sequence. [ Example:
struct B { };
struct D : private B { };
void f() {
static_cast<D*>((B*)0);
// error: B is a private base of D
static_cast<int B::*>((int D::*)0);
// error: B is a private base of D
}
— end example ]
8
The lvalue-to-rvalue (7.1), array-to-pointer (7.2), and function-to-pointer (7.3) conversions are applied to the
operand. Such a static_cast is subject to the restriction that the explicit conversion does not cast away
constness (8.5.1.11), and the following additional rules for specific cases:
§ 8.5.1.9
105
9
A value of a scoped enumeration type (10.2) can be explicitly converted to an integral type. When that type
is cv bool, the resulting value is false if the original value is zero and true for all other values. For the
remaining integral types, the value is unchanged if the original value can be represented by the specified type.
Otherwise, the resulting value is unspecified. A value of a scoped enumeration type can also be explicitly
converted to a floating-point type; the result is the same as that of converting from the original value to the
floating-point type.
10
A value of integral or enumeration type can be explicitly converted to a complete enumeration type. If the
enumeration type has a fixed underlying type, the value is first converted to that type by integral conversion,
if necessary, and then to the enumeration type. If the enumeration type does not have a fixed underlying
type, the value is unchanged if the original value is within the range of the enumeration values (10.2), and
otherwise, the behavior is undefined. A value of floating-point type can also be explicitly converted to an
enumeration type. The resulting value is the same as converting the original value to the underlying type of
the enumeration (7.10), and subsequently to the enumeration type.
11
A prvalue of type “pointer to cv1 B”, where B is a class type, can be converted to a prvalue of type “pointer
to cv2 D”, where D is a class derived (Clause 13) from B, if cv2 is the same cv-qualification as, or greater
cv-qualification than, cv1. If B is a virtual base class of D or a base class of a virtual base class of D, or if
no valid standard conversion from “pointer to D” to “pointer to B” exists (7.11), the program is ill-formed.
The null pointer value (7.11) is converted to the null pointer value of the destination type. If the prvalue of
type “pointer to cv1 B” points to a B that is actually a subobject of an object of type D, the resulting pointer
points to the enclosing object of type D. Otherwise, the behavior is undefined.
12
A prvalue of type “pointer to member of D of type cv1 T” can be converted to a prvalue of type “pointer
to member of B of type cv2 T”, where B is a base class (Clause 13) of D, if cv2 is the same cv-qualification
as, or greater cv-qualification than, cv1.72 If no valid standard conversion from “pointer to member of B of
type T” to “pointer to member of D of type T” exists (7.12), the program is ill-formed. The null member
pointer value (7.12) is converted to the null member pointer value of the destination type. If class B contains
the original member, or is a base or derived class of the class containing the original member, the resulting
pointer to member points to the original member. Otherwise, the behavior is undefined. [Note: Although
class B need not contain the original member, the dynamic type of the object with which indirection through
the pointer to member is performed must contain the original member; see 8.5.4.
— end note ]
13
A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T”, where T is
an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. If the original
pointer value represents the address A of a byte in memory and A does not satisfy the alignment requirement
of T, then the resulting pointer value is unspecified. Otherwise, if the original pointer value points to an
object a, and there is an object b of type T (ignoring cv-qualification) that is pointer-interconvertible (6.7.2)
with a, the result is a pointer to b. Otherwise, the pointer value is unchanged by the conversion. [ Example:
T* p1 = new T;
const T* p2 = static_cast<const T*>(static_cast<void*>(p1));
bool b = p1 == p2;
// b will have the value true.
— end example ]
8.5.1.10
Reinterpret cast
[expr.reinterpret.cast]
1
The result of the expression reinterpret_cast<T>(v) is the result of converting the expression v to type T.
If T is an lvalue reference type or an rvalue reference to function type, the result is an lvalue; if T is an rvalue
reference to object type, the result is an xvalue; otherwise, the result is a prvalue and the lvalue-to-rvalue (7.1),
array-to-pointer (7.2), and function-to-pointer (7.3) standard conversions are performed on the expression v.
Conversions that can be performed explicitly using reinterpret_cast are listed below. No other conversion
can be performed explicitly using reinterpret_cast.
2
The reinterpret_cast operator shall not cast away constness (8.5.1.11). An expression of integral, enumer-
ation, pointer, or pointer-to-member type can be explicitly converted to its own type; such a cast yields the
value of its operand.
3
[ Note: The mapping performed by reinterpret_cast might, or might not, produce a representation different
from the original value.
— end note ]
4
A pointer can be explicitly converted to any integral type large enough to hold it. The mapping function is
implementation-defined. [ Note: It is intended to be unsurprising to those who know the addressing structure
72) Function types (including those used in pointer-to-member-function types) are never cv-qualified; see 11.3.5.
§ 8.5.1.10
106
of the underlying machine.
— end note ] A value of type std::nullptr_t can be converted to an integral
type; the conversion has the same meaning and validity as a conversion of (void*)0 to the integral type.
[Note: A reinterpret_cast cannot be used to convert a value of any type to the type std::nullptr_t.
— end note ]
5
A value of integral type or enumeration type can be explicitly converted to a pointer. A pointer converted to
an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will
have its original value; mappings between pointers and integers are otherwise implementation-defined. [ Note:
Except as described in 6.6.4.4.3, the result of such a conversion will not be a safely-derived pointer value.
— end note ]
6
A function pointer can be explicitly converted to a function pointer of a different type. [ Note: The effect of
calling a function through a pointer to a function type (11.3.5) that is not the same as the type used in the
definition of the function is undefined.
— end note ] Except that converting a prvalue of type “pointer to T1”
to the type “pointer to T2” (where T1 and T2 are function types) and back to its original type yields the
original pointer value, the result of such a pointer conversion is unspecified. [Note: See also 7.11 for more
details of pointer conversions.
— end note ]
7
An object pointer can be explicitly converted to an object pointer of a different type.73 When a prvalue v of
object pointer type is converted to the object pointer type “pointer to cv T”, the result is static_cast<cv
T*>(static_cast<cv void*>(v)). [ Note: Converting a prvalue of type “pointer to T1” to the type “pointer
to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than
those of T1) and back to its original type yields the original pointer value.
— end note ]
8
Converting a function pointer to an object pointer type or vice versa is conditionally-supported. The meaning
of such a conversion is implementation-defined, except that if an implementation supports conversions in both
directions, converting a prvalue of one type to the other type and back, possibly with different cv-qualification,
shall yield the original pointer value.
9
The null pointer value (7.11) is converted to the null pointer value of the destination type. [Note: A null
pointer constant of type std::nullptr_t cannot be converted to a pointer type, and a null pointer constant
of integral type is not necessarily converted to a null pointer value.
— end note ]
10
A prvalue of type “pointer to member of X of type T1” can be explicitly converted to a prvalue of a different
type “pointer to member of Y of type T2” if T1 and T2 are both function types or both object types.74 The
null member pointer value (7.12) is converted to the null member pointer value of the destination type. The
result of this conversion is unspecified, except in the following cases:
(10.1)
—
converting a prvalue of type “pointer to member function” to a different pointer-to-member-function
type and back to its original type yields the original pointer-to-member value.
(10.2)
—
converting a prvalue of type “pointer to data member of X of type T1” to the type “pointer to data
member of Y of type T2” (where the alignment requirements of T2 are no stricter than those of T1) and
back to its original type yields the original pointer-to-member value.
11
A glvalue expression of type T1, designating an object x, can be cast to the type “reference to T2” if
an expression of type “pointer to T1” can be explicitly converted to the type “pointer to T2” using a
reinterpret_cast. The result is that of *reinterpret_cast<T2 *>(p) where p is a pointer to x of type
“pointer to T1”. No temporary is created, no copy is made, and no constructors (15.1) or conversion
functions (15.3) are called.75
8.5.1.11
Const cast
[expr.const.cast]
1
The result of the expression const_cast<T>(v) is of type T. If T is an lvalue reference to object type, the result
is an lvalue; if T is an rvalue reference to object type, the result is an xvalue; otherwise, the result is a prvalue
and the lvalue-to-rvalue (7.1), array-to-pointer (7.2), and function-to-pointer (7.3) standard conversions are
performed on the expression v. Conversions that can be performed explicitly using const_cast are listed
below. No other conversion shall be performed explicitly using const_cast.
2
[Note: Subject to the restrictions in this subclause, an expression may be cast to its own type using a
const_cast operator.
— end note ]
73) The types may have different cv-qualifiers, subject to the overall restriction that a reinterpret_cast cannot cast away
constness.
74) T1 and T2 may have different cv-qualifiers, subject to the overall restriction that a reinterpret_cast cannot cast away
constness.
75) This is sometimes referred to as a type pun when the result refers to the same object as the source glvalue.
§ 8.5.1.11
107
3
For two similar types T1 and T2 (7.5), a prvalue of type T1 may be explicitly converted to the type T2 using
a const_cast. The result of a const_cast refers to the original entity. [ Example:
typedef int *A[3];
// array of 3 pointer to int
typedef const int *const CA[3];
// array of 3 const pointer to const int
CA &&r = A{}; // OK, reference binds to temporary array object after qualification conversion to type CA
A &&r1 = const_cast<A>(CA{});
// error: temporary array decayed to pointer
A &&r2 = const_cast<A&&>(CA{});
// OK
— end example ]
4
For two object types T1 and T2, if a pointer to T1 can be explicitly converted to the type “pointer to T2”
using a const_cast, then the following conversions can also be made:
(4.1)
—
an lvalue of type T1 can be explicitly converted to an lvalue of type T2 using the cast const_cast<T2&>;
(4.2)
—
a glvalue of type T1 can be explicitly converted to an xvalue of type T2 using the cast const_cast<T2&&>;
and
(4.3)
—
if T1 is a class type, a prvalue of type T1 can be explicitly converted to an xvalue of type T2 using the
cast const_cast<T2&&>.
The result of a reference const_cast refers to the original object if the operand is a glvalue and to the result
of applying the temporary materialization conversion (7.4) otherwise.
5
A null pointer value (7.11) is converted to the null pointer value of the destination type. The null member
pointer value (7.12) is converted to the null member pointer value of the destination type.
6
[Note: Depending on the type of the object, a write operation through the pointer, lvalue or pointer
to data member resulting from a const_cast that casts away a const-qualifier76 may produce undefined
behavior (10.1.7.1).
— end note ]
7
A conversion from a type T1 to a type T2 casts away constness if T1 and T2 are different, there is a
cv-decomposition (7.5) of T1 yielding n such that T2 has a cv-decomposition of the form
cv2
0
0
cv2
1
1
··· cv2
n−1
n−1 cvn U2,
and there is no qualification conversion that converts T1 to
cv2
0
0
cv2
1 P1 ·
·· cv2
n−1
n−1 cvn U1.
8
Casting from an lvalue of type T1 to an lvalue of type T2 using an lvalue reference cast or casting from an
expression of type T1 to an xvalue of type T2 using an rvalue reference cast casts away constness if a cast
from a prvalue of type “pointer to T1” to the type “pointer to T2” casts away constness.
9
[Note: Some conversions which involve only changes in cv-qualification cannot be done using const_cast.
For instance, conversions between pointers to functions are not covered because such conversions lead to
values whose use causes undefined behavior. For the same reasons, conversions between pointers to member
functions, and in particular, the conversion from a pointer to a const member function to a pointer to a
non-const member function, are not covered.
— end note ]
8.5.2
Unary expressions
[expr.unary]
1
Expressions with unary operators group right-to-left.
unary-expression:
postfix-expression
++ cast-expression
-- cast-expression
unary-operator cast-expression
sizeof unary-expression
sizeof ( type-id )
sizeof ... ( identifier )
alignof ( type-id )
noexcept-expression
new-expression
delete-expression
76) const_cast is not limited to conversions that cast away a const-qualifier.
§ 8.5.2
108
unary-operator: one of
* & + - ! ~
8.5.2.1
Unary operators
[expr.unary.op]
1
The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an
object type, or a pointer to a function type and the result is an lvalue referring to the object or function
to which the expression points. If the type of the expression is “pointer to T”, the type of the result is “T”.
[Note: Indirection through a pointer to an incomplete type (other than cv void) is valid. The lvalue thus
obtained can be used in limited ways (to initialize a reference, for example); this lvalue must not be converted
to a prvalue, see 7.1.
— end note ]
2
The result of each of the following unary operators is a prvalue.
3
The result of the unary & operator is a pointer to its operand. The operand shall be an lvalue or a qualified-id.
If the operand is a qualified-id naming a non-static or variant member m of some class C with type T, the
result has type “pointer to member of class C of type T” and is a prvalue designating C::m. Otherwise, if
the type of the expression is T, the result has type “pointer to T” and is a prvalue that is the address of
the designated object (6.6.1) or a pointer to the designated function. [Note: In particular, the address of
an object of type “cv T” is “pointer to cv T”, with the same cv-qualification.
— end note ] For purposes
of pointer arithmetic (8.5.6) and comparison (8.5.9, 8.5.10), an object that is not an array element whose
address is taken in this way is considered to belong to an array with one element of type T. [ Example:
struct A { int i; };
struct B : A { };
... &B::i ...
// has type int A::*
int a;
int* p1 = &a;
int* p2 = p1 + 1;
// defined behavior
bool b = p2 > p1;
// defined behavior, with value true
— end example ] [ Note: A pointer to member formed from a mutable non-static data member (10.1.1) does
not reflect the mutable specifier associated with the non-static data member.
— end note ]
4
A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed
in parentheses.
[Note: That is, the expression &(qualified-id), where the qualified-id is enclosed in
parentheses, does not form an expression of type “pointer to member”. Neither does qualified-id, because
there is no implicit conversion from a qualified-id for a non-static member function to the type “pointer to
member function” as there is from an lvalue of function type to the type “pointer to function” (7.3). Nor is
&unqualified-id a pointer to member, even within the scope of the unqualified-id’s class.
— end note ]
5
If & is applied to an lvalue of incomplete class type and the complete type declares operator&(), it is
unspecified whether the operator has the built-in meaning or the operator function is called. The operand of
& shall not be a bit-field.
6
The address of an overloaded function (Clause 16) can be taken only in a context that uniquely determines
which version of the overloaded function is referred to (see 16.4). [ Note: Since the context might determine
whether the operand is a static or non-static member function, the context can also affect whether the
expression has type “pointer to function” or “pointer to member function”.
— end note ]
7
The operand of the unary + operator shall have arithmetic, unscoped enumeration, or pointer type and the
result is the value of the argument. Integral promotion is performed on integral or enumeration operands.
The type of the result is the type of the promoted operand.
8
The operand of the unary - operator shall have arithmetic or unscoped enumeration type and the result
is the negation of its operand. Integral promotion is performed on integral or enumeration operands. The
negative of an unsigned quantity is computed by subtracting its value from 2n, where n is the number of bits
in the promoted operand. The type of the result is the type of the promoted operand.
9
The operand of the logical negation operator ! is contextually converted to bool (Clause 7); its value is
true if the converted operand is false and false otherwise. The type of the result is bool.
10
The operand of ~ shall have integral or unscoped enumeration type; the result is the ones’ complement of its
operand. Integral promotions are performed. The type of the result is the type of the promoted operand.
There is an ambiguity in the grammar when ~ is followed by a class-name or decltype-specifier. The ambiguity
is resolved by treating ~ as the unary complement operator rather than as the start of an unqualified-id
naming a destructor. [Note: Because the grammar does not permit an operator to follow the ., ->, or ::
§ 8.5.2.1
109
tokens, a ~ followed by a class-name or decltype-specifier in a member access expression or qualified-id is
unambiguously parsed as a destructor name.
— end note ]
8.5.2.2
Increment and decrement
[expr.pre.incr]
1
The operand of prefix ++ is modified by adding 1. The operand shall be a modifiable lvalue. The type of the
operand shall be an arithmetic type other than cv bool, or a pointer to a completely-defined object type. The
result is the updated operand; it is an lvalue, and it is a bit-field if the operand is a bit-field. The expression
++x is equivalent to x+=1. [ Note: See the discussions of addition (8.5.6) and assignment operators (8.5.18)
for information on conversions.
— end note ]
2
The operand of prefix -- is modified by subtracting 1. The requirements on the operand of prefix -- and
the properties of its result are otherwise the same as those of prefix ++. [Note: For postfix increment and
decrement, see 8.5.1.6.
— end note ]
8.5.2.3
Sizeof
[expr.sizeof]
1
The sizeof operator yields the number of bytes in the object representation of its operand. The operand
is either an expression, which is an unevaluated operand (8.2), or a parenthesized type-id. The sizeof
operator shall not be applied to an expression that has function or incomplete type, to the parenthesized
name of such types, or to a glvalue that designates a bit-field. sizeof(char), sizeof(signed char) and
sizeof(unsigned char) are 1. The result of sizeof applied to any other fundamental type (6.7.1) is
implementation-defined. [ Note: In particular, sizeof(bool), sizeof(char16_t), sizeof(char32_t), and
sizeof(wchar_t) are implementation-defined.77
— end note ]
[Note: See 6.6.1 for the definition of byte
and 6.7 for the definition of object representation.
— end note ]
2
When applied to a reference or a reference type, the result is the size of the referenced type. When applied
to a class, the result is the number of bytes in an object of that class including any padding required for
placing objects of that type in an array. The size of a most derived class shall be greater than zero (6.6.2).
The result of applying sizeof to a base class subobject is the size of the base class type.78 When applied
to an array, the result is the total number of bytes in the array. This implies that the size of an array of n
elements is n times the size of an element.
3
The sizeof operator can be applied to a pointer to a function, but shall not be applied directly to a function.
4
The lvalue-to-rvalue (7.1), array-to-pointer (7.2), and function-to-pointer (7.3) standard conversions are not
applied to the operand of sizeof. If the operand is a prvalue, the temporary materialization conversion (7.4)
is applied.
5
The identifier in a sizeof... expression shall name a parameter pack. The sizeof... operator yields
the number of arguments provided for the parameter pack identifier. A sizeof... expression is a pack
expansion (17.6.3). [ Example:
template<class... Types>
struct count {
static const std::size_t value = sizeof...(Types);
};
— end example ]
6
The result of sizeof and sizeof... is a constant of type std::size_t. [ Note: std::size_t is defined in
the standard header <cstddef> (21.2.1, 21.2.4).
— end note ]
8.5.2.4
New
[expr.new]
1
The new-expression attempts to create an object of the type-id (11.1) or new-type-id to which it is applied.
The type of that object is the allocated type. This type shall be a complete object type, but not an abstract
class type or array thereof (6.6.2, 6.7, 13.4). [ Note: Because references are not objects, references cannot be
created by new-expressions.
— end note ] [ Note: The type-id may be a cv-qualified type, in which case the
object created by the new-expression has a cv-qualified type.
— end note ]
new-expression:
::opt new new-placementopt new-type-id new-initializeropt
::opt new new-placementopt ( type-id ) new-initializeropt
77) sizeof(bool) is not required to be 1.
78) The actual size of a base class subobject may be less than the result of applying sizeof to the subobject, due to virtual
base classes and less strict padding requirements on base class subobjects.
§ 8.5.2.4
110
new-placement:
( expression-list )
new-type-id:
type-specifier-seq new-declaratoropt
new-declarator:
ptr-operator new-declaratoropt
noptr-new-declarator
noptr-new-declarator:
[ expression ] attribute-specifier-seqopt
noptr-new-declarator [ constant-expression ] attribute-specifier-seqopt
new-initializer:
( expression-listopt )
braced-init-list
Entities created by a new-expression have dynamic storage duration (6.6.4.4). [ Note: The lifetime of such
an entity is not necessarily restricted to the scope in which it is created.
— end note ] If the entity is a
non-array object, the result of the new-expression is a pointer to the object created. If it is an array, the
result of the new-expression is a pointer to the initial element of the array.
2
If a placeholder type (10.1.7.4) appears in the type-specifier-seq of a new-type-id or type-id of a new-expression,
the allocated type is deduced as follows: Let init be the new-initializer, if any, and T be the new-type-id or
type-id of the new-expression, then the allocated type is the type deduced for the variable x in the invented
declaration (10.1.7.4):
T x init
;
[ Example:
new auto(1);
// allocated type is int
auto x = new auto(’a’);
// allocated type is char, x is of type char*
template<class T> struct A { A(T, T); };
auto y = new A{1, 2};
// allocated type is A<int>
— end example ]
3
The new-type-id in a new-expression is the longest possible sequence of new-declarator s. [ Note: This prevents
ambiguities between the declarator operators &, &&, *, and [] and their expression counterparts.
— end
note ]
[ Example:
new int * i;
// syntax error: parsed as (new int*) i, not as (new int)*i
The * is the pointer declarator and not the multiplication operator.
— end example ]
4
[ Note: Parentheses in a new-type-id of a new-expression can have surprising effects. [ Example:
new int(*[10])();
// error
is ill-formed because the binding is
(new int) (*[10])();
// error
Instead, the explicitly parenthesized version of the new operator can be used to create objects of compound
types (6.7.2):
new (int (*[10])());
allocates an array of 10 pointers to functions (taking no argument and returning int).
— end example ]
— end note ]
5
When the allocated object is an array (that is, the noptr-new-declarator syntax is used or the new-type-id or
type-id denotes an array type), the new-expression yields a pointer to the initial element (if any) of the array.
[Note: Both new int and new int[10] have type int* and the type of new int[i][10] is int (*)[10]
— end note ] The attribute-specifier-seq in a noptr-new-declarator appertains to the associated array type.
6
Every constant-expression in a noptr-new-declarator shall be a converted constant expression (8.6) of type
std::size_t and shall evaluate to a strictly positive value. The expression in a noptr-new-declarator is
implicitly converted to std::size_t.
[Example: Given the definition int n = 42, new float[n][5] is
well-formed (because n is the expression of a noptr-new-declarator ), but new float[5][n] is ill-formed
(because n is not a constant expression).
— end example ]
§ 8.5.2.4
111
|
|