|
|
|
7
The expression in a noptr-new-declarator is erroneous if:
(7.1)
—
the expression is of non-class type and its value before converting to std::size_t is less than zero;
(7.2)
—
the expression is of class type and its value before application of the second standard conversion
(16.3.3.1.2)79 is less than zero;
(7.3)
—
its value is such that the size of the allocated object would exceed the implementation-defined limit
(Annex B); or
(7.4)
—
the new-initializer is a braced-init-list and the number of array elements for which initializers are
provided (including the terminating ’\0’ in a string literal (5.13.5)) exceeds the number of elements to
initialize.
If the expression is erroneous after converting to std::size_t:
(7.5)
—
if the expression is a core constant expression, the program is ill-formed;
(7.6)
—
otherwise, an allocation function is not called; instead
(7.6.1)
—
if the allocation function that would have been called has a non-throwing exception specification
(18.4), the value of the new-expression is the null pointer value of the required result type;
(7.6.2)
—
otherwise, the new-expression terminates by throwing an exception of a type that would match a
handler (18.3) of type std::bad_array_new_length (21.6.3.2).
When the value of the expression is zero, the allocation function is called to allocate an array with no
elements.
8
A new-expression may obtain storage for the object by calling an allocation function (6.6.4.4.1). If the
new-expression terminates by throwing an exception, it may release storage by calling a deallocation
function (6.6.4.4.2). If the allocated type is a non-array type, the allocation function’s name is operator
new and the deallocation function’s name is operator delete. If the allocated type is an array type, the
allocation function’s name is operator new[] and the deallocation function’s name is operator delete[].
[ Note: An implementation shall provide default definitions for the global allocation functions (6.6.4.4, 21.6.2.1,
21.6.2.2). A C++ program can provide alternative definitions of these functions (20.5.4.6) and/or class-specific
versions (15.5). The set of allocation and deallocation functions that may be called by a new-expression may
include functions that do not perform allocation or deallocation; for example, see 21.6.2.3.
— end note ]
9
If the new-expression begins with a unary :: operator, the allocation function’s name is looked up in the
global scope. Otherwise, if the allocated type is a class type T or array thereof, the allocation function’s name
is looked up in the scope of T. If this lookup fails to find the name, or if the allocated type is not a class type,
the allocation function’s name is looked up in the global scope.
10
An implementation is allowed to omit a call to a replaceable global allocation function (21.6.2.1, 21.6.2.2).
When it does so, the storage is instead provided by the implementation or provided by extending the allocation
of another new-expression. The implementation may extend the allocation of a new-expression e1 to provide
storage for a new-expression e2 if the following would be true were the allocation not extended:
(10.1)
—
the evaluation of e1 is sequenced before the evaluation of e2, and
(10.2)
—
e2 is evaluated whenever e1 obtains storage, and
(10.3)
—
both e1 and e2 invoke the same replaceable global allocation function, and
(10.4)
—
if the allocation function invoked by e1 and e2 is throwing, any exceptions thrown in the evaluation of
either e1 or e2 would be first caught in the same handler, and
(10.5)
—
the pointer values produced by e1 and e2 are operands to evaluated delete-expressions, and
(10.6)
—
the evaluation of e2 is sequenced before the evaluation of the delete-expression whose operand is the
pointer value produced by e1.
[ Example:
void mergeable(int x) {
// These allocations are safe for merging:
std::unique_ptr<char[]> a{new (std::nothrow) char[8]};
std::unique_ptr<char[]> b{new (std::nothrow) char[8]};
std::unique_ptr<char[]> c{new (std::nothrow) char[x]};
79) If the conversion function returns a signed integer type, the second standard conversion converts to the unsigned type
std::size_t and thus thwarts any attempt to detect a negative value afterwards.
§ 8.5.2.4
112
g(a.get(), b.get(), c.get());
}
void unmergeable(int x) {
std::unique_ptr<char[]> a{new char[8]};
try {
// Merging this allocation would change its catch handler.
std::unique_ptr<char[]> b{new char[x]};
} catch (const std::bad_alloc& e) {
std::cerr << "Allocation failed: " << e.what() << std::endl;
throw;
}
}
— end example ]
11
When a new-expression calls an allocation function and that allocation has not been extended, the new-
expression passes the amount of space requested to the allocation function as the first argument of type
std::size_t. That argument shall be no less than the size of the object being created; it may be greater
than the size of the object being created only if the object is an array. For arrays of char, unsigned char,
and std::byte, the difference between the result of the new-expression and the address returned by the
allocation function shall be an integral multiple of the strictest fundamental alignment requirement (6.6.5) of
any object type whose size is no greater than the size of the array being created. [ Note: Because allocation
functions are assumed to return pointers to storage that is appropriately aligned for objects of any type with
fundamental alignment, this constraint on array allocation overhead permits the common idiom of allocating
character arrays into which objects of other types will later be placed.
— end note ]
12
When a new-expression calls an allocation function and that allocation has been extended, the size argument
to the allocation call shall be no greater than the sum of the sizes for the omitted calls as specified above,
plus the size for the extended call had it not been extended, plus any padding necessary to align the allocated
objects within the allocated memory.
13
The new-placement syntax is used to supply additional arguments to an allocation function; such an expression
is called a placement new-expression.
14
Overload resolution is performed on a function call created by assembling an argument list. The first
argument is the amount of space requested, and has type std::size_t. If the type of the allocated object
has new-extended alignment, the next argument is the type’s alignment, and has type std::align_val_t. If
the new-placement syntax is used, the initializer-clauses in its expression-list are the succeeding arguments.
If no matching function is found and the allocated object type has new-extended alignment, the alignment
argument is removed from the argument list, and overload resolution is performed again.
15
[ Example:
(15.1)
—
new T results in one of the following calls:
operator new(sizeof(T))
operator new(sizeof(T), std::align_val_t(alignof(T)))
(15.2)
—
new(2,f) T results in one of the following calls:
operator new(sizeof(T), 2, f)
operator new(sizeof(T), std::align_val_t(alignof(T)), 2, f)
(15.3)
—
new T[5] results in one of the following calls:
operator new[](sizeof(T) * 5 + x)
operator new[](sizeof(T) * 5 + x, std::align_val_t(alignof(T)))
(15.4)
—
new(2,f) T[5] results in one of the following calls:
operator new[](sizeof(T) * 5 + x, 2, f)
operator new[](sizeof(T) * 5 + x, std::align_val_t(alignof(T)), 2, f)
Here, each instance of x is a non-negative unspecified value representing array allocation overhead; the
result of the new-expression will be offset by this amount from the value returned by operator new[].
This overhead may be applied in all array new-expressions, including those referencing the library function
operator new[](std::size_t, void*) and other placement allocation functions. The amount of overhead
may vary from one invocation of new to another.
— end example ]
§ 8.5.2.4
113
16
[Note: Unless an allocation function has a non-throwing exception specification (18.4), it indicates failure
to allocate storage by throwing a std::bad_alloc exception (6.6.4.4.1, Clause 18, 21.6.3.1); it returns a
non-null pointer otherwise. If the allocation function has a non-throwing exception specification, it returns
null to indicate failure to allocate storage and a non-null pointer otherwise.
— end note ] If the allocation
function is a non-allocating form (21.6.2.3) that returns null, the behavior is undefined. Otherwise, if the
allocation function returns null, initialization shall not be done, the deallocation function shall not be called,
and the value of the new-expression shall be null.
17
[Note: When the allocation function returns a value other than null, it must be a pointer to a block of
storage in which space for the object has been reserved. The block of storage is assumed to be appropriately
aligned and of the requested size. The address of the created object will not necessarily be the same as that
of the block if the object is an array.
— end note ]
18
A new-expression that creates an object of type T initializes that object as follows:
(18.1)
—
If the new-initializer is omitted, the object is default-initialized (11.6). [ Note: If no initialization is
performed, the object has an indeterminate value.
— end note ]
(18.2)
—
Otherwise, the new-initializer is interpreted according to the initialization rules of 11.6 for direct-
initialization.
19
The invocation of the allocation function is sequenced before the evaluations of expressions in the new-initializer.
Initialization of the allocated object is sequenced before the value computation of the new-expression.
20
If the new-expression creates an object or an array of objects of class type, access and ambiguity control
are done for the allocation function, the deallocation function (15.5), and the constructor (15.1). If the
new-expression creates an array of objects of class type, the destructor is potentially invoked (15.4).
21
If any part of the object initialization described above80 terminates by throwing an exception and a suitable
deallocation function can be found, the deallocation function is called to free the memory in which the object
was being constructed, after which the exception continues to propagate in the context of the new-expression.
If no unambiguous matching deallocation function can be found, propagating the exception does not cause
the object’s memory to be freed. [ Note: This is appropriate when the called allocation function does not
allocate memory; otherwise, it is likely to result in a memory leak.
— end note ]
22
If the new-expression begins with a unary :: operator, the deallocation function’s name is looked up in the
global scope. Otherwise, if the allocated type is a class type T or an array thereof, the deallocation function’s
name is looked up in the scope of T. If this lookup fails to find the name, or if the allocated type is not a
class type or array thereof, the deallocation function’s name is looked up in the global scope.
23
A declaration of a placement deallocation function matches the declaration of a placement allocation function
if it has the same number of parameters and, after parameter transformations (11.3.5), all parameter types
except the first are identical. If the lookup finds a single matching deallocation function, that function will
be called; otherwise, no deallocation function will be called. If the lookup finds a usual deallocation function
with a parameter of type std::size_t (6.6.4.4.2) and that function, considered as a placement deallocation
function, would have been selected as a match for the allocation function, the program is ill-formed. For
a non-placement allocation function, the normal deallocation function lookup is used to find the matching
deallocation function (8.5.2.5) [ Example:
struct S {
// Placement allocation function:
static void* operator new(std::size_t, std::size_t);
// Usual (non-placement) deallocation function:
static void operator delete(void*, std::size_t);
};
S* p = new (0) S;
// ill-formed: non-placement deallocation function matches
// placement allocation function
— end example ]
24
If a new-expression calls a deallocation function, it passes the value returned from the allocation function
call as the first argument of type void*. If a placement deallocation function is called, it is passed the same
additional arguments as were passed to the placement allocation function, that is, the same arguments as
80) This may include evaluating a new-initializer and/or calling a constructor.
§ 8.5.2.4
114
those specified with the new-placement syntax. If the implementation is allowed to introduce a temporary
object or make a copy of any argument as part of the call to the allocation function, it is unspecified whether
the same object is used in the call to both the allocation and deallocation functions.
8.5.2.5
Delete
[expr.delete]
1
The delete-expression operator destroys a most derived object (6.6.2) or array created by a new-expression.
delete-expression:
::opt delete cast-expression
::opt delete [ ] cast-expression
The first alternative is a single-object delete expression, and the second is an array delete expression. Whenever
the delete keyword is immediately followed by empty square brackets, it shall be interpreted as the second
alternative.81 The operand shall be of pointer to object type or of class type. If of class type, the operand is
contextually implicitly converted (Clause 7) to a pointer to object type.82 The delete-expression’s result has
type void.
2
If the operand has a class type, the operand is converted to a pointer type by calling the above-mentioned
conversion function, and the converted operand is used in place of the original operand for the remainder of
this subclause. In a single-object delete expression, the value of the operand of delete may be a null pointer
value, a pointer to a non-array object created by a previous new-expression, or a pointer to a subobject (6.6.2)
representing a base class of such an object (Clause 13). If not, the behavior is undefined. In an array delete
expression, the value of the operand of delete may be a null pointer value or a pointer value that resulted
from a previous array new-expression.83
If not, the behavior is undefined.
[Note: This means that the
syntax of the delete-expression must match the type of the object allocated by new, not the syntax of the
new-expression.
— end note ] [ Note: A pointer to a const type can be the operand of a delete-expression;
it is not necessary to cast away the constness (8.5.1.11) of the pointer expression before it is used as the
operand of the delete-expression.
— end note ]
3
In a single-object delete expression, if the static type of the object to be deleted is different from its dynamic
type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type
shall have a virtual destructor or the behavior is undefined. In an array delete expression, if the dynamic
type of the object to be deleted differs from its static type, the behavior is undefined.
4
The cast-expression in a delete-expression shall be evaluated exactly once.
5
If the object being deleted has incomplete class type at the point of deletion and the complete class has a
non-trivial destructor or a deallocation function, the behavior is undefined.
6
If the value of the operand of the delete-expression is not a null pointer value, the delete-expression will
invoke the destructor (if any) for the object or the elements of the array being deleted. In the case of an
array, the elements will be destroyed in order of decreasing address (that is, in reverse order of the completion
of their constructor; see 15.6.2).
7
If the value of the operand of the delete-expression is not a null pointer value, then:
(7.1)
—
If the allocation call for the new-expression for the object to be deleted was not omitted and the
allocation was not extended (8.5.2.4), the delete-expression shall call a deallocation function (6.6.4.4.2).
The value returned from the allocation call of the new-expression shall be passed as the first argument
to the deallocation function.
(7.2)
—
Otherwise, if the allocation was extended or was provided by extending the allocation of another
new-expression, and the delete-expression for every other pointer value produced by a new-expression
that had storage provided by the extended new-expression has been evaluated, the delete-expression shall
call a deallocation function. The value returned from the allocation call of the extended new-expression
shall be passed as the first argument to the deallocation function.
(7.3)
—
Otherwise, the delete-expression will not call a deallocation function.
[ Note: The deallocation function is called regardless of whether the destructor for the object or some element
of the array throws an exception.
— end note ] If the value of the operand of the delete-expression is a null
pointer value, it is unspecified whether a deallocation function will be called as described above.
81) A lambda expression with a lambda-introducer that consists of empty square brackets can follow the delete keyword if the
lambda expression is enclosed in parentheses.
82) This implies that an object cannot be deleted using a pointer of type void* because void is not an object type.
83) For nonzero-length arrays, this is the same as a pointer to the first element of the array created by that new-expression.
Zero-length arrays do not have a first element.
§ 8.5.2.5
115
8
[ Note: An implementation provides default definitions of the global deallocation functions operator delete
for non-arrays (21.6.2.1) and operator delete[] for arrays (21.6.2.2). A C++ program can provide alternative
definitions of these functions (20.5.4.6), and/or class-specific versions (15.5).
— end note ]
9
When the keyword delete in a delete-expression is preceded by the unary :: operator, the deallocation
function’s name is looked up in global scope. Otherwise, the lookup considers class-specific deallocation
functions (15.5). If no class-specific deallocation function is found, the deallocation function’s name is looked
up in global scope.
10
If deallocation function lookup finds more than one usual deallocation function, the function to be called is
selected as follows:
(10.1)
—
If the type has new-extended alignment, a function with a parameter of type std::align_val_t is
preferred; otherwise a function without such a parameter is preferred. If exactly one preferred function
is found, that function is selected and the selection process terminates. If more than one preferred
function is found, all non-preferred functions are eliminated from further consideration.
(10.2)
—
If the deallocation functions have class scope, the one without a parameter of type std::size_t is
selected.
(10.3)
—
If the type is complete and if, for the second alternative (delete array) only, the operand is a pointer to
a class type with a non-trivial destructor or a (possibly multi-dimensional) array thereof, the function
with a parameter of type std::size_t is selected.
(10.4)
—
Otherwise, it is unspecified whether a deallocation function with a parameter of type std::size_t is
selected.
11
When a delete-expression is executed, the selected deallocation function shall be called with the address of
the most-derived object in a single-object delete expression, or the address of the object suitably adjusted for
the array allocation overhead (8.5.2.4) in an array delete expression, as its first argument. If a deallocation
function with a parameter of type std::align_val_t is used, the alignment of the type of the object to
be deleted is passed as the corresponding argument. If a deallocation function with a parameter of type
std::size_t is used, the size of the most-derived type, or of the array plus allocation overhead, respectively,
is passed as the corresponding argument.84 [Note: If this results in a call to a usual deallocation function,
and either the first argument was not the result of a prior call to a usual allocation function or the second
argument was not the corresponding argument in said call, the behavior is undefined (21.6.2.1, 21.6.2.2).
— end note ]
12
Access and ambiguity control are done for both the deallocation function and the destructor (15.4, 15.5).
8.5.2.6
Alignof
[expr.alignof]
1
An alignof expression yields the alignment requirement of its operand type. The operand shall be a type-id
representing a complete object type, or an array thereof, or a reference to one of those types.
2
The result is an integral constant of type std::size_t.
3
When alignof is applied to a reference type, the result is the alignment of the referenced type. When
alignof is applied to an array type, the result is the alignment of the element type.
8.5.2.7
noexcept operator
[expr.unary.noexcept]
1
The noexcept operator determines whether the evaluation of its operand, which is an unevaluated operand
(8.2), can throw an exception (18.1).
noexcept-expression:
noexcept ( expression )
2
The result of the noexcept operator is a constant of type bool and is a prvalue.
3
The result of the noexcept operator is true unless the expression is potentially-throwing (18.4).
8.5.3
Explicit type conversion (cast notation)
[expr.cast]
1
The result of the expression (T) cast-expression is of type T. The result is an lvalue if T is an lvalue reference
type or an rvalue reference to function type and an xvalue if T is an rvalue reference to object type; otherwise
the result is a prvalue. [Note: If T is a non-class type that is cv-qualified, the cv-qualifiers are discarded
when determining the type of the resulting prvalue; see 8.2.
— end note ]
84) If the static type of the object to be deleted is complete and is different from the dynamic type, and the destructor is not
virtual, the size might be incorrect, but that case is already undefined, as stated above.
§ 8.5.3
116
2
An explicit type conversion can be expressed using functional notation (8.5.1.3), a type conversion operator
(dynamic_cast, static_cast, reinterpret_cast, const_cast), or the cast notation.
cast-expression:
unary-expression
( type-id ) cast-expression
3
Any type conversion not mentioned below and not explicitly defined by the user (15.3) is ill-formed.
4
The conversions performed by
(4.1)
—
a const_cast (8.5.1.11),
(4.2)
—
a static_cast (8.5.1.9),
(4.3)
—
a static_cast followed by a const_cast,
(4.4)
—
a reinterpret_cast (8.5.1.10), or
(4.5)
—
a reinterpret_cast followed by a const_cast,
can be performed using the cast notation of explicit type conversion. The same semantic restrictions
and behaviors apply, with the exception that in performing a static_cast in the following situations the
conversion is valid even if the base class is inaccessible:
(4.6)
—
a pointer to an object of derived class type or an lvalue or rvalue of derived class type may be explicitly
converted to a pointer or reference to an unambiguous base class type, respectively;
(4.7)
—
a pointer to member of derived class type may be explicitly converted to a pointer to member of an
unambiguous non-virtual base class type;
(4.8)
—
a pointer to an object of an unambiguous non-virtual base class type, a glvalue of an unambiguous
non-virtual base class type, or a pointer to member of an unambiguous non-virtual base class type
may be explicitly converted to a pointer, a reference, or a pointer to member of a derived class type,
respectively.
If a conversion can be interpreted in more than one of the ways listed above, the interpretation that appears
first in the list is used, even if a cast resulting from that interpretation is ill-formed. If a conversion can be
interpreted in more than one way as a static_cast followed by a const_cast, the conversion is ill-formed.
[ Example:
struct A { };
struct I1 : A { };
struct I2 : A { };
struct D : I1, I2 { };
A* foo( D* p ) {
return (A*)( p );
// ill-formed static_cast interpretation
}
— end example ]
5
The operand of a cast using the cast notation can be a prvalue of type “pointer to incomplete class type”.
The destination type of a cast using the cast notation can be “pointer to incomplete class type”. If both the
operand and destination types are class types and one or both are incomplete, it is unspecified whether the
static_cast or the reinterpret_cast interpretation is used, even if there is an inheritance relationship
between the two classes.
[Note: For example, if the classes were defined later in the translation unit, a
multi-pass compiler would be permitted to interpret a cast between pointers to the classes as if the class
types were complete at the point of the cast.
— end note ]
8.5.4
Pointer-to-member operators
[expr.mptr.oper]
1
The pointer-to-member operators ->* and .* group left-to-right.
pm-expression:
cast-expression
pm-expression .* cast-expression
pm-expression ->* cast-expression
2
The binary operator .* binds its second operand, which shall be of type “pointer to member of T” to its first
operand, which shall be a glvalue of class T or of a class of which T is an unambiguous and accessible base
class. The result is an object or a function of the type specified by the second operand.
§ 8.5.4
117
3
The binary operator ->* binds its second operand, which shall be of type “pointer to member of T” to its first
operand, which shall be of type “pointer to U” where U is either T or a class of which T is an unambiguous
and accessible base class. The expression E1->*E2 is converted into the equivalent form (*(E1)).*E2.
4
Abbreviating pm-expression.*cast-expression as E1.*E2, E1 is called the object expression. If the dynamic
type of E1 does not contain the member to which E2 refers, the behavior is undefined. Otherwise, the
expression E1 is sequenced before the expression E2.
5
The restrictions on cv-qualification, and the manner in which the cv-qualifiers of the operands are combined
to produce the cv-qualifiers of the result, are the same as the rules for E1.E2 given in 8.5.1.5. [Note: It is
not possible to use a pointer to member that refers to a mutable member to modify a const class object. For
example,
struct S {
S() : i(0) { }
mutable int i;
};
void f()
{
const S cs;
int S::* pm = &S::i;
// pm refers to mutable member S::i
cs.*pm = 88;
// ill-formed: cs is a const object
}
— end note ]
6
If the result of .* or ->* is a function, then that result can be used only as the operand for the function call
operator (). [ Example:
(ptr_to_obj->*ptr_to_mfct)(10);
calls the member function denoted by ptr_to_mfct for the object pointed to by ptr_to_obj. — end example ]
In a .* expression whose object expression is an rvalue, the program is ill-formed if the second operand is a
pointer to member function whose ref-qualifier is &, unless its cv-qualifier-seq is const. In a .* expression
whose object expression is an lvalue, the program is ill-formed if the second operand is a pointer to member
function whose ref-qualifier is &&. The result of a .* expression whose second operand is a pointer to a data
member is an lvalue if the first operand is an lvalue and an xvalue otherwise. The result of a .* expression
whose second operand is a pointer to a member function is a prvalue. If the second operand is the null
member pointer value (7.12), the behavior is undefined.
8.5.5
Multiplicative operators
[expr.mul]
1
The multiplicative operators *, /, and % group left-to-right.
multiplicative-expression:
pm-expression
multiplicative-expression * pm-expression
multiplicative-expression / pm-expression
multiplicative-expression % pm-expression
2
The operands of * and / shall have arithmetic or unscoped enumeration type; the operands of % shall have
integral or unscoped enumeration type. The usual arithmetic conversions (8.3) are performed on the operands
and determine the type of the result.
3
The binary * operator indicates multiplication.
4
The binary / operator yields the quotient, and the binary % operator yields the remainder from the division
of the first expression by the second. If the second operand of / or % is zero the behavior is undefined. For
integral operands the / operator yields the algebraic quotient with any fractional part discarded;85 if the
quotient a/b is representable in the type of the result, (a/b)*b + a%b is equal to a; otherwise, the behavior
of both a/b and a%b is undefined.
8.5.6
Additive operators
[expr.add]
1
The additive operators + and - group left-to-right. The usual arithmetic conversions (8.3) are performed for
operands of arithmetic or enumeration type.
85) This is often called truncation towards zero.
§ 8.5.6
118
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
For addition, either both operands shall have arithmetic or unscoped enumeration type, or one operand shall
be a pointer to a completely-defined object type and the other shall have integral or unscoped enumeration
type.
2
For subtraction, one of the following shall hold:
(2.1)
—
both operands have arithmetic or unscoped enumeration type; or
(2.2)
—
both operands are pointers to cv-qualified or cv-unqualified versions of the same completely-defined
object type; or
(2.3)
—
the left operand is a pointer to a completely-defined object type and the right operand has integral or
unscoped enumeration type.
3
The result of the binary + operator is the sum of the operands. The result of the binary - operator is the
difference resulting from the subtraction of the second operand from the first.
4
When an expression that has integral type is added to or subtracted from a pointer, the result has the type
of the pointer operand. If the expression P points to element x[i] of an array object x with n elements,86
the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) element
x[i + j] if 0 ≤ i + j ≤ n; otherwise, the behavior is undefined. Likewise, the expression P - J points to the
(possibly-hypothetical) element x[i − j] if 0 ≤ i − j ≤ n; otherwise, the behavior is undefined.
5
When two pointers to elements of the same array object are subtracted, the type of the result is an
implementation-defined signed integral type; this type shall be the same type that is defined as std::ptrdiff_-
t in the <cstddef> header (21.2). If the expressions P and Q point to, respectively, elements x[i] and x[j]
of the same array object x, the expression P - Q has the value i − j; otherwise, the behavior is undefined.
[ Note: If the value i − j is not in the range of representable values of type std::ptrdiff_t, the behavior is
undefined.
— end note ]
6
For addition or subtraction, if the expressions P or Q have type “pointer to cv T”, where T and the array
element type are not similar (7.5), the behavior is undefined. [ Note: In particular, a pointer to a base class
cannot be used for pointer arithmetic when the array contains objects of a derived class type.
— end note ]
7
If the value 0 is added to or subtracted from a null pointer value, the result is a null pointer value. If two null
pointer values are subtracted, the result compares equal to the value 0 converted to the type std::ptrdiff_t.
8.5.7
Shift operators
[expr.shift]
1
The shift operators << and >> group left-to-right.
shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
The operands shall be of integral or unscoped enumeration type and integral promotions are performed. The
type of the result is that of the promoted left operand. The behavior is undefined if the right operand is
negative, or greater than or equal to the length in bits of the promoted left operand.
2
The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. If E1 has an unsigned
type, the value of the result is E1 × 2E2, reduced modulo one more than the maximum value representable in
the result type. Otherwise, if E1 has a signed type and non-negative value, and E1 × 2E2 is representable
in the corresponding unsigned type of the result type, then that value, converted to the result type, is the
resulting value; otherwise, the behavior is undefined.
3
The value of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed
type and a non-negative value, the value of the result is the integral part of the quotient of E1/2E2. If E1 has
a signed type and a negative value, the resulting value is implementation-defined.
4
The expression E1 is sequenced before the expression E2.
86) An object that is not an array element is considered to belong to a single-element array for this purpose; see 8.5.2.1. A
pointer past the last element of an array x of n elements is considered to be equivalent to a pointer to a hypothetical element
x[n] for this purpose; see 6.7.2.
§ 8.5.7
119
8.5.8
Three-way comparison operator
[expr.spaceship]
1
The three-way comparison operator groups left-to-right.
compare-expression:
shift-expression
compare-expression <=> shift-expression
2
The expression p <=> q is a prvalue indicating whether p is less than, equal to, greater than, or incomparable
with q.
3
If one of the operands is of type bool and the other is not, the program is ill-formed.
4
If both operands have arithmetic types, the usual arithmetic conversions (8.3) are applied to the operands.
Then:
(4.1)
—
If a narrowing conversion (11.6.4) is required, other than from an integral type to a floating point type,
the program is ill-formed.
—
(4.2)
Otherwise, if the operands have integral type, the result is of type std::strong_ordering. The
result is std::strong_ordering::equal if both operands are arithmetically equal, std::strong_-
ordering::less if the first operand is arithmetically less than the second operand, and std::strong_-
ordering::greater otherwise.
—
(4.3)
Otherwise, the operands have floating-point type, and the result is of type std::partial_ordering.
The expression a <=> b yields std::partial_ordering::less if a is less than b, std::partial_-
ordering::greater if a is greater than b, std::partial_ordering::equivalent if a is equivalent
to b, and std::partial_ordering::unordered otherwise.
5
If both operands have the same enumeration type E, the operator yields the result of converting the operands
to the underlying type of E and applying <=> to the converted operands.
6
If at least one of the operands is of pointer type, array-to-pointer conversions (7.2), pointer conversions (7.11),
function pointer conversions (7.13), and qualification conversions (7.5) are performed on both operands to
bring them to their composite pointer type (8.2.2). If at least one of the operands is of pointer-to-member type,
pointer-to-member conversions (7.12) and qualification conversions (7.5) are performed on both operands to
bring them to their composite pointer type (8.2.2). If both operands are null pointer constants, but not both
of integer type, pointer conversions (7.11) are performed on both operands to bring them to their composite
pointer type (8.2.2). In all cases, after the conversions, the operands shall have the same type. [Note: If
both of the operands are arrays, array-to-pointer conversions (7.2) are not applied.
— end note ]
7
If the composite pointer type is a function pointer type, a pointer-to-member type, or std::nullptr_t,
the result is of type std::strong_equality; the result is std::strong_equality::equal if the (possibly
converted) operands compare equal (8.5.10) and std::strong_equality::unequal if they compare unequal,
otherwise the result of the operator is unspecified.
8
If the composite pointer type is an object pointer type, p <=> q is of type std::strong_ordering. If
two pointer operands p and q compare equal (8.5.10), p <=> q yields std::strong_ordering::equal; if p
and q compare unequal, p <=> q yields std::strong_ordering::less if q compares greater than p and
std::strong_ordering::greater if p compares greater than q (8.5.9). Otherwise, the result is unspecified.
9
Otherwise, the program is ill-formed.
10
The five comparison category types (21.10.2) (the types std::strong_ordering, std::strong_equality,
std::weak_ordering, std::weak_equality, and std::partial_ordering) are not predefined; if the header
<compare> is not included prior to a use of such a class type - even an implicit use in which the type is
not named (e.g., via the auto specifier (10.1.7.4) in a defaulted three-way comparison (15.9.2) or use of the
built-in operator) - the program is ill-formed.
8.5.9
Relational operators
[expr.rel]
1
The relational operators group left-to-right. [ Example: a<b<c means (a<b)<c and not (a<b)&&(b<c).
— end
example ]
relational-expression:
compare-expression
relational-expression < compare-expression
relational-expression > compare-expression
relational-expression <= compare-expression
relational-expression >= compare-expression
§ 8.5.9
120
The operands shall have arithmetic, enumeration, or pointer type. The operators < (less than), > (greater
than), <= (less than or equal to), and >= (greater than or equal to) all yield false or true. The type of the
result is bool.
2
The usual arithmetic conversions (8.3) are performed on operands of arithmetic or enumeration type. If both
operands are pointers, pointer conversions (7.11) and qualification conversions (7.5) are performed to bring
them to their composite pointer type (8.2). After conversions, the operands shall have the same type.
3
Comparing unequal pointers to objects87 is defined as follows:
(3.1)
—
If two pointers point to different elements of the same array, or to subobjects thereof, the pointer to
the element with the higher subscript compares greater.
(3.2)
—
If two pointers point to different non-static data members of the same object, or to subobjects of such
members, recursively, the pointer to the later declared member compares greater provided the two
members have the same access control (Clause 14) and provided their class is not a union.
(3.3)
—
Otherwise, neither pointer compares greater than the other.
4
If two operands p and q compare equal (8.5.10), p<=q and p>=q both yield true and p<q and p>q both yield
false. Otherwise, if a pointer p compares greater than a pointer q, p>=q, p>q, q<=p, and q<p all yield true
and p<=q, p<q, q>=p, and q>p all yield false. Otherwise, the result of each of the operators is unspecified.
5
If both operands (after conversions) are of arithmetic or enumeration type, each of the operators shall yield
true if the specified relationship is true and false if it is false.
8.5.10
Equality operators
[expr.eq]
equality-expression:
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression
1
The == (equal to) and the != (not equal to) operators group left-to-right. The operands shall have arithmetic,
enumeration, pointer, or pointer-to-member type, or type std::nullptr_t. The operators == and != both
yield true or false, i.e., a result of type bool. In each case below, the operands shall have the same type
after the specified conversions have been applied.
2
If at least one of the operands is a pointer, pointer conversions (7.11), function pointer conversions (7.13),
and qualification conversions (7.5) are performed on both operands to bring them to their composite pointer
type (8.2). Comparing pointers is defined as follows:
(2.1)
—
If one pointer represents the address of a complete object, and another pointer represents the address
one past the last element of a different complete object,88 the result of the comparison is unspecified.
(2.2)
—
Otherwise, if the pointers are both null, both point to the same function, or both represent the same
address (6.7.2), they compare equal.
(2.3)
—
Otherwise, the pointers compare unequal.
3
If at least one of the operands is a pointer to member, pointer-to-member conversions (7.12) and qualification
conversions (7.5) are performed on both operands to bring them to their composite pointer type (8.2).
Comparing pointers to members is defined as follows:
(3.1)
—
If two pointers to members are both the null member pointer value, they compare equal.
(3.2)
—
If only one of two pointers to members is the null member pointer value, they compare unequal.
(3.3)
—
If either is a pointer to a virtual member function, the result is unspecified.
(3.4)
—
If one refers to a member of class C1 and the other refers to a member of a different class C2, where
neither is a base class of the other, the result is unspecified. [ Example:
struct A {};
struct B : A { int x; };
struct C : A { int x; };
87) An object that is not an array element is considered to belong to a single-element array for this purpose; see 8.5.2.1. A
pointer past the last element of an array x of n elements is considered to be equivalent to a pointer to a hypothetical element
x[n] for this purpose; see 6.7.2.
88) An object that is not an array element is considered to belong to a single-element array for this purpose; see 8.5.2.1.
§ 8.5.10
121
int A::*bx = (int(A::*))&B::x;
int A::*cx = (int(A::*))&C::x;
bool b1 = (bx == cx);
// unspecified
— end example ]
(3.5)
—
If both refer to (possibly different) members of the same union (12.3), they compare equal.
(3.6)
—
Otherwise, two pointers to members compare equal if they would refer to the same member of the
same most derived object (6.6.2) or the same subobject if indirection with a hypothetical object of the
associated class type were performed, otherwise they compare unequal. [ Example:
struct B {
int f();
};
struct L : B { };
struct R : B { };
struct D : L, R { };
int (B::*pb)() = &B::f;
int (L::*pl)() = pb;
int (R::*pr)() = pb;
int (D::*pdl)() = pl;
int (D::*pdr)() = pr;
bool x = (pdl == pdr);
// false
bool y = (pb == pl);
// true
— end example ]
4
Two operands of type std::nullptr_t or one operand of type std::nullptr_t and the other a null pointer
constant compare equal.
5
If two operands compare equal, the result is true for the == operator and false for the != operator. If two
operands compare unequal, the result is false for the == operator and true for the != operator. Otherwise,
the result of each of the operators is unspecified.
6
If both operands are of arithmetic or enumeration type, the usual arithmetic conversions (8.3) are performed
on both operands; each of the operators shall yield true if the specified relationship is true and false if it is
false.
8.5.11
Bitwise AND operator
[expr.bit.and]
and-expression:
equality-expression
and-expression & equality-expression
1
The usual arithmetic conversions (8.3) are performed; the result is the bitwise AND function of the operands.
The operator applies only to integral or unscoped enumeration operands.
8.5.12
Bitwise exclusive OR operator
[expr.xor]
exclusive-or-expression:
and-expression
exclusive-or-expression ^ and-expression
1
The usual arithmetic conversions (8.3) are performed; the result is the bitwise exclusive OR function of the
operands. The operator applies only to integral or unscoped enumeration operands.
8.5.13
Bitwise inclusive OR operator
[expr.or]
inclusive-or-expression:
exclusive-or-expression
inclusive-or-expression | exclusive-or-expression
1
The usual arithmetic conversions (8.3) are performed; the result is the bitwise inclusive OR function of its
operands. The operator applies only to integral or unscoped enumeration operands.
§ 8.5.13
122
8.5.14
Logical AND operator
[expr.log.and]
logical-and-expression:
inclusive-or-expression
logical-and-expression && inclusive-or-expression
1
The && operator groups left-to-right. The operands are both contextually converted to bool (Clause 7).
The result is true if both operands are true and false otherwise. Unlike &, && guarantees left-to-right
evaluation: the second operand is not evaluated if the first operand is false.
2
The result is a bool. If the second expression is evaluated, every value computation and side effect associated
with the first expression is sequenced before every value computation and side effect associated with the
second expression.
8.5.15
Logical OR operator
[expr.log.or]
logical-or-expression:
logical-and-expression
logical-or-expression || logical-and-expression
1
The || operator groups left-to-right. The operands are both contextually converted to bool (Clause 7). The
result is true if either of its operands is true, and false otherwise. Unlike |, || guarantees left-to-right
evaluation; moreover, the second operand is not evaluated if the first operand evaluates to true.
2
The result is a bool. If the second expression is evaluated, every value computation and side effect associated
with the first expression is sequenced before every value computation and side effect associated with the
second expression.
8.5.16
Conditional operator
[expr.cond]
conditional-expression:
logical-or-expression
logical-or-expression ? expression : assignment-expression
1
Conditional expressions group right-to-left. The first expression is contextually converted to bool (Clause 7).
It is evaluated and if it is true, the result of the conditional expression is the value of the second expression,
otherwise that of the third expression. Only one of the second and third expressions is evaluated. Every value
computation and side effect associated with the first expression is sequenced before every value computation
and side effect associated with the second or third expression.
2
If either the second or the third operand has type void, one of the following shall hold:
(2.1)
—
The second or the third operand (but not both) is a (possibly parenthesized) throw-expression (8.5.17);
the result is of the type and value category of the other. The conditional-expression is a bit-field if that
operand is a bit-field.
(2.2)
—
Both the second and the third operands have type void; the result is of type void and is a prvalue.
[ Note: This includes the case where both operands are throw-expressions.
— end note ]
3
Otherwise, if the second and third operand are glvalue bit-fields of the same value category and of types cv1
T and cv2 T, respectively, the operands are considered to be of type cv T for the remainder of this subclause,
where cv is the union of cv1 and cv2.
4
Otherwise, if the second and third operand have different types and either has (possibly cv-qualified) class
type, or if both are glvalues of the same value category and the same type except for cv-qualification, an
attempt is made to form an implicit conversion sequence (16.3.3.1) from each of those operands to the type
of the other. [ Note: Properties such as access, whether an operand is a bit-field, or whether a conversion
function is deleted are ignored for that determination.
— end note ] Attempts are made to form an implicit
conversion sequence from an operand expression E1 of type T1 to a target type related to the type T2 of the
operand expression E2 as follows:
(4.1)
—
If E2 is an lvalue, the target type is “lvalue reference to T2”, subject to the constraint that in the
conversion the reference must bind directly (11.6.3) to an lvalue.
(4.2)
—
If E2 is an xvalue, the target type is “rvalue reference to T2”, subject to the constraint that the reference
must bind directly.
(4.3)
—
If E2 is a prvalue or if neither of the conversion sequences above can be formed and at least one of the
operands has (possibly cv-qualified) class type:
§ 8.5.16
123
(4.3.1)
—
if T1 and T2 are the same class type (ignoring cv-qualification), or one is a base class of the other,
and T2 is at least as cv-qualified as T1, the target type is T2,
(4.3.2)
—
otherwise, the target type is the type that E2 would have after applying the lvalue-to-rvalue (7.1),
array-to-pointer (7.2), and function-to-pointer (7.3) standard conversions.
Using this process, it is determined whether an implicit conversion sequence can be formed from the second
operand to the target type determined for the third operand, and vice versa. If both sequences can be
formed, or one can be formed but it is the ambiguous conversion sequence, the program is ill-formed. If no
conversion sequence can be formed, the operands are left unchanged and further checking is performed as
described below. Otherwise, if exactly one conversion sequence can be formed, that conversion is applied to
the chosen operand and the converted operand is used in place of the original operand for the remainder of
this subclause. [ Note: The conversion might be ill-formed even if an implicit conversion sequence could be
formed.
— end note ]
5
If the second and third operands are glvalues of the same value category and have the same type, the result
is of that type and value category and it is a bit-field if the second or the third operand is a bit-field, or if
both are bit-fields.
6
Otherwise, the result is a prvalue. If the second and third operands do not have the same type, and either
has (possibly cv-qualified) class type, overload resolution is used to determine the conversions (if any) to be
applied to the operands (16.3.1.2, 16.6). If the overload resolution fails, the program is ill-formed. Otherwise,
the conversions thus determined are applied, and the converted operands are used in place of the original
operands for the remainder of this subclause.
7
Lvalue-to-rvalue (7.1), array-to-pointer (7.2), and function-to-pointer (7.3) standard conversions are performed
on the second and third operands. After those conversions, one of the following shall hold:
(7.1)
—
The second and third operands have the same type; the result is of that type and the result object is
initialized using the selected operand.
(7.2)
—
The second and third operands have arithmetic or enumeration type; the usual arithmetic conversions
(8.3) are performed to bring them to a common type, and the result is of that type.
(7.3)
—
One or both of the second and third operands have pointer type; pointer conversions (7.11), function
pointer conversions (7.13), and qualification conversions (7.5) are performed to bring them to their
composite pointer type (8.2). The result is of the composite pointer type.
(7.4)
—
One or both of the second and third operands have pointer-to-member type; pointer to member
conversions (7.12) and qualification conversions (7.5) are performed to bring them to their composite
pointer type (8.2). The result is of the composite pointer type.
(7.5)
—
Both the second and third operands have type std::nullptr_t or one has that type and the other is
a null pointer constant. The result is of type std::nullptr_t.
8.5.17
Throwing an exception
[expr.throw]
throw-expression:
throw assignment-expressionopt
1
A throw-expression is of type void.
2
Evaluating a throw-expression with an operand throws an exception (18.1); the type of the exception object
is determined by removing any top-level cv-qualifier s from the static type of the operand and adjusting the
type from “array of T” or function type T to “pointer to T”.
3
A throw-expression with no operand rethrows the currently handled exception (18.3). The exception is
reactivated with the existing exception object; no new exception object is created. The exception is no
longer considered to be caught. [ Example: Code that must be executed because of an exception, but cannot
completely handle the exception itself, can be written like this:
try {
// ...
} catch (...) {
// catch all exceptions
// respond (partially) to exception
throw;
// pass the exception to some other handler
}
— end example ]
§ 8.5.17
124
4
If no exception is presently being handled, evaluating a throw-expression with no operand calls std::
terminate() (18.5.1).
8.5.18
Assignment and compound assignment operators
[expr.ass]
1
The assignment operator (=) and the compound assignment operators all group right-to-left. All require a
modifiable lvalue as their left operand; their result is an lvalue referring to the left operand. The result in all
cases is a bit-field if the left operand is a bit-field. In all cases, the assignment is sequenced after the value
computation of the right and left operands, and before the value computation of the assignment expression.
The right operand is sequenced before the left operand. With respect to an indeterminately-sequenced
function call, the operation of a compound assignment 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
compound assignment operator. — end note ]
assignment-expression:
conditional-expression
logical-or-expression assignment-operator initializer-clause
throw-expression
assignment-operator: one of
= *= /= %= += -= >>= <<= &= ^= |=
2
In simple assignment (=), the value of the expression replaces that of the object referred to by the left
operand.
3
If the left operand is not of class type, the expression is implicitly converted (Clause 7) to the cv-unqualified
type of the left operand.
4
If the left operand is of class type, the class shall be complete. Assignment to objects of a class is defined by
the copy/move assignment operator (15.8, 16.5.3).
5
[ Note: For class objects, assignment is not in general the same as initialization (11.6, 15.1, 15.6, 15.8).
— end
note ]
6
When the left operand of an assignment operator is a bit-field that cannot represent the value of the expression,
the resulting value of the bit-field is implementation-defined.
7
The behavior of an expression of the form E1 op = E2 is equivalent to E1 = E1 op E2 except that E1 is
evaluated only once. In += and -=, E1 shall either have arithmetic type or be a pointer to a possibly
cv-qualified completely-defined object type. In all other cases, E1 shall have arithmetic type.
8
If the value being stored in an object is read via another object that overlaps in any way the storage of the
first object, then the overlap shall be exact and the two objects shall have the same type, otherwise the
behavior is undefined. [ Note: This restriction applies to the relationship between the left and right sides of
the assignment operation; it is not a statement about how the target of the assignment may be aliased in
general. See 8.2.1.
— end note ]
9
A braced-init-list may appear on the right-hand side of
(9.1)
—
an assignment to a scalar, in which case the initializer list shall have at most a single element. The
meaning of x = {v}, where T is the scalar type of the expression x, is that of x = T{v}. The meaning
of x = {} is x = T{}.
(9.2)
—
an assignment to an object of class type, in which case the initializer list is passed as the argument to
the assignment operator function selected by overload resolution (16.5.3, 16.3).
[ Example:
complex<double> z;
z = { 1,2 };
// meaning z.operator=({1,2})
z += { 1, 2 };
// meaning z.operator+=({1,2})
int a, b;
a = b = { 1 };
// meaning a=b=1;
a = { 1 } = b;
// syntax error
— end example ]
8.5.19
Comma operator
[expr.comma]
1
The comma operator groups left-to-right.
§ 8.5.19
125
expression:
assignment-expression
expression , assignment-expression
A pair of expressions separated by a comma is evaluated left-to-right; the left expression is a discarded-value
expression (8.2). Every value computation and side effect associated with the left expression is sequenced
before every value computation and side effect associated with the right expression. The type and value of the
result are the type and value of the right operand; the result is of the same value category as its right operand,
and is a bit-field if its right operand is a bit-field. If the right operand is a temporary expression (15.2), the
result is a temporary expression.
2
In contexts where comma is given a special meaning, [ Example: in lists of arguments to functions (8.5.1.2)
and lists of initializers (11.6) — end example ] the comma operator as described in this subclause can appear
only in parentheses. [ Example:
f(a, (t=3, t+2), c);
has three arguments, the second of which has the value 5.
— end example ]
8.6
Constant expressions
[expr.const]
1
Certain contexts require expressions that satisfy additional requirements as detailed in this subclause; other
contexts have different semantics depending on whether or not an expression satisfies these requirements.
Expressions that satisfy these requirements, assuming that copy elision is performed, are called constant
expressions. [ Note: Constant expressions can be evaluated during translation. — end note ]
constant-expression:
conditional-expression
2
An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract
machine (6.8.1), would evaluate one of the following expressions:
(2.1)
—
this (8.4.2), except in a constexpr function or a constexpr constructor that is being evaluated as part
of e;
(2.2)
—
an invocation of a function other than a constexpr constructor for a literal class, a constexpr function,
or an implicit invocation of a trivial destructor (15.4) [Note: Overload resolution (16.3) is applied as
usual — end note ] ;
(2.3)
—
an invocation of an undefined constexpr function or an undefined constexpr constructor;
(2.4)
—
an invocation of an instantiated constexpr function or constexpr constructor that fails to satisfy the
requirements for a constexpr function or constexpr constructor (10.1.5);
(2.5)
—
an expression that would exceed the implementation-defined limits (see Annex B);
(2.6)
—
an operation that would have undefined behavior as specified in Clause 4 through Clause 19 of this
document [ Note: including, for example, signed integer overflow (8.2), certain pointer arithmetic (8.5.6),
division by zero (8.5.5), or certain shift operations (8.5.7) — end note ] ;
(2.7)
—
an lvalue-to-rvalue conversion (7.1) unless it is applied to
(2.7.1)
—
a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const
object with a preceding initialization, initialized with a constant expression, or
(2.7.2)
—
a non-volatile glvalue that refers to a subobject of a string literal (5.13.5), or
(2.7.3)
—
a non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers to
a non-mutable subobject of such an object, or
(2.7.4)
—
a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within
the evaluation of e;
(2.8)
—
an lvalue-to-rvalue conversion (7.1) that is applied to a glvalue that refers to a non-active member of a
union or a subobject thereof;
(2.9)
—
an invocation of an implicitly-defined copy/move constructor or copy/move assignment operator for a
union whose active member (if any) is mutable, unless the lifetime of the union object began within the
evaluation of e;
(2.10)
—
an assignment expression (8.5.18) or invocation of an assignment operator (15.8) that would change the
active member of a union;
§
8.6
126
(2.11)
—
an id-expression that refers to a variable or data member of reference type unless the reference has a
preceding initialization and either
(2.11.1)
—
it is initialized with a constant expression or
(2.11.2)
—
its lifetime began within the evaluation of e;
(2.12)
—
in a lambda-expression, a reference to this or to a variable with automatic storage duration defined
outside that lambda-expression, where the reference would be an odr-use (6.2, 8.4.5); [ Example:
void g() {
const int n = 0;
[=] {
constexpr int i = n;
// OK, n is not odr-used and not captured here
constexpr int j = *&n; // ill-formed, &n would be an odr-use of n
};
}
— end example ] [ Note: If the odr-use occurs in an invocation of a function call operator of a closure
type, it no longer refers to this or to an enclosing automatic variable due to the transformation (8.4.5.2)
of the id-expression into an access of the corresponding data member. [ Example:
auto monad = [](auto v) { return [=] { return v; }; };
auto bind = [](auto m) {
return [=](auto fvm) { return fvm(m()); };
};
// OK to have captures to automatic objects created during constant expression evaluation.
static_assert(bind(monad(2))(monad)() == monad(2)());
— end example ]
— end note ]
(2.13)
—
a conversion from type cv void* to a pointer-to-object type;
(2.14)
—
a dynamic cast (8.5.1.7);
(2.15)
—
a reinterpret_cast (8.5.1.10);
(2.16)
—
a pseudo-destructor call (8.5.1.4);
(2.17)
—
modification of an object (8.5.18, 8.5.1.6, 8.5.2.2) unless it is applied to a non-volatile lvalue of literal
type that refers to a non-volatile object whose lifetime began within the evaluation of e;
(2.18)
—
a typeid expression (8.5.1.8) whose operand is a glvalue of a polymorphic class type;
(2.19)
—
a new-expression (8.5.2.4);
(2.20)
—
a delete-expression (8.5.2.5);
(2.21)
—
a three-way comparison (8.5.8) comparing pointers that do not point to the same complete object or to
any subobject thereof;
(2.22)
—
a relational (8.5.9) or equality (8.5.10) operator where the result is unspecified; or
(2.23)
—
a throw-expression (8.5.17).
If
e satisfies the constraints of a core constant expression, but evaluation of e would evaluate an operation
that has undefined behavior as specified in Clause 20 through Clause 33 of this document, it is unspecified
whether e is a core constant expression.
[ Example:
int x;
// not constant
struct A {
constexpr A(bool b) : m(b?42:x) { }
int m;
};
constexpr int v = A(true).m;
// OK: constructor call initializes m with the value 42
constexpr int w = A(false).m;
// error: initializer for m is x, which is non-constant
constexpr int f1(int k) {
constexpr int x = k;
// error: x is not initialized by a constant expression
§ 8.6
127
// because lifetime of k began outside the initializer of x
return x;
}
constexpr int f2(int k) {
int x = k;
// OK: not required to be a constant expression
// because x is not constexpr
return x;
}
constexpr int incr(int &n) {
return ++n;
}
constexpr int g(int k) {
constexpr int x = incr(k);
// error: incr(k) is not a core constant expression
// because lifetime of k began outside the expression incr(k)
return x;
}
constexpr int h(int k) {
int x = incr(k);
// OK: incr(k) is not required to be a core constant expression
return x;
}
constexpr int y = h(1);
// OK: initializes y with the value 2
// h(1) is a core constant expression because
// the lifetime of k begins inside h(1)
— end example ]
3
An integral constant expression is an expression of integral or unscoped enumeration type, implicitly converted
to a prvalue, where the converted expression is a core constant expression. [ Note: Such expressions may be
used as bit-field lengths (12.2.4), as enumerator initializers if the underlying type is not fixed (10.2), and as
alignments (10.6.2).
— end note ]
4
If an expression of literal class type is used in a context where an integral constant expression is required,
then that expression is contextually implicitly converted (Clause 7) to an integral or unscoped enumeration
type and the selected conversion function shall be constexpr. [ Example:
struct A {
constexpr A(int i) : val(i) { }
constexpr operator int() const { return val; }
constexpr operator long() const { return 42; }
private:
int val;
};
template<int> struct X { };
constexpr A a = alignof(int);
alignas(a) int n;
// error: ambiguous conversion
struct B { int n : a; };
// error: ambiguous conversion
— end example ]
5
A converted constant expression of type T is an expression, implicitly converted to type T, where the converted
expression is a constant expression and the implicit conversion sequence contains only
(5.1)
—
user-defined conversions,
(5.2)
—
lvalue-to-rvalue conversions (7.1),
(5.3)
—
array-to-pointer conversions (7.2),
(5.4)
—
function-to-pointer conversions (7.3),
(5.5)
—
qualification conversions (7.5),
(5.6)
—
integral promotions (7.6),
(5.7)
—
integral conversions (7.8) other than narrowing conversions (11.6.4),
(5.8)
—
null pointer conversions (7.11) from std::nullptr_t,
(5.9)
—
null member pointer conversions (7.12) from std::nullptr_t, and
(5.10)
—
function pointer conversions (7.13),
§ 8.6
128
and where the reference binding (if any) binds directly.
[Note: Such expressions may be used in new
expressions (8.5.2.4), as case expressions (9.4.2), as enumerator initializers if the underlying type is fixed (10.2),
as array bounds (11.3.4), and as non-type template arguments (17.3).
— end note ] A contextually converted
constant expression of type bool is an expression, contextually converted to bool (Clause 7), where the
converted expression is a constant expression and the conversion sequence contains only the conversions
above.
6
A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted
result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies
the following constraints:
(6.1)
—
if the value is an object of class type, each non-static data member of reference type refers to an entity
that is a permitted result of a constant expression,
(6.2)
—
if the value is of pointer type, it contains the address of an object with static storage duration, the
address past the end of such an object (8.5.6), the address of a function, or a null pointer value, and
(6.3)
—
if the value is an object of class or array type, each subobject satisfies these constraints for the value.
An entity is a permitted result of a constant expression if it is an object with static storage duration that is
either not a temporary object or is a temporary object whose value satisfies the above constraints, or it is a
function.
7
[Note: Since this document imposes no restrictions on the accuracy of floating-point operations, it is
unspecified whether the evaluation of a floating-point expression during translation yields the same result as
the evaluation of the same expression (or the same operations on the same values) during program execution.89
[ Example:
bool f() {
char array[1 + int(1 + 0.2 - 0.1 - 0.1)];
// Must be evaluated during translation
int size = 1 + int(1 + 0.2 - 0.1 - 0.1);
// May be evaluated at runtime
return sizeof(array) == size;
}
It is unspecified whether the value of f() will be true or false.
— end example ]
— end note ]
8
An expression is potentially constant evaluated if it is:
(8.1)
—
a potentially-evaluated expression (6.2),
(8.2)
—
a constraint-expression, including one formed from the constraint-logical-or-expression of a requires-
clause,
(8.3)
—
an immediate subexpression of a braced-init-list,90
(8.4)
—
an expression of the form & cast-expression that occurs within a templated entity,91 or
(8.5)
—
a subexpression of one of the above that is not a subexpression of a nested unevaluated operand.
A function or variable is needed for constant evaluation if it is:
(8.6)
—
a constexpr function that is named by an expression (6.2) that is potentially constant evaluated, or
(8.7)
—
a variable whose name appears as a potentially constant evaluated expression that is either a constexpr
variable or is of non-volatile const-qualified integral type or of reference type.
89) Nonetheless, implementations should provide consistent results, irrespective of whether the evaluation was performed during
translation and/or during program execution.
90) Constant evaluation may be necessary to determine whether a narrowing conversion is performed (11.6.4).
91) Constant evaluation may be necessary to determine whether such an expression is value-dependent (17.7.2.3).
§ 8.6
129
9
Statements
[stmt.stmt]
1
Except as indicated, statements are executed in sequence.
statement:
labeled-statement
attribute-specifier-seqopt expression-statement
attribute-specifier-seqopt compound-statement
attribute-specifier-seqopt selection-statement
attribute-specifier-seqopt iteration-statement
attribute-specifier-seqopt jump-statement
declaration-statement
attribute-specifier-seqopt try-block
init-statement:
expression-statement
simple-declaration
condition:
expression
attribute-specifier-seqopt decl-specifier-seq declarator brace-or-equal-initializer
The optional attribute-specifier-seq appertains to the respective statement.
2
The rules for conditions apply both to selection-statements and to the for and while statements (9.5).
The declarator shall not specify a function or an array. The decl-specifier-seq shall not define a class or
enumeration. If the auto type-specifier appears in the decl-specifier-seq, the type of the identifier being
declared is deduced from the initializer as described in 10.1.7.4.
3
A name introduced by a declaration in a condition (either introduced by the decl-specifier-seq or the declarator
of the condition) is in scope from its point of declaration until the end of the substatements controlled by the
condition. If the name is redeclared in the outermost block of a substatement controlled by the condition,
the declaration that redeclares the name is ill-formed. [ Example:
if (int x = f()) {
int x;
// ill-formed, redeclaration of x
}
else {
int x;
// ill-formed, redeclaration of x
}
— end example ]
4
The value of a condition that is an initialized declaration in a statement other than a switch statement is the
value of the declared variable contextually converted to bool (Clause 7). If that conversion is ill-formed, the
program is ill-formed. The value of a condition that is an initialized declaration in a switch statement is the
value of the declared variable if it has integral or enumeration type, or of that variable implicitly converted
to integral or enumeration type otherwise. The value of a condition that is an expression is the value of the
expression, contextually converted to bool for statements other than switch; if that conversion is ill-formed,
the program is ill-formed. The value of the condition will be referred to as simply “the condition” where the
usage is unambiguous.
5
If a condition can be syntactically resolved as either an expression or the declaration of a block-scope name,
it is interpreted as a declaration.
6
In the decl-specifier-seq of a condition, each decl-specifier shall be either a type-specifier or constexpr.
9.1
Labeled statement
[stmt.label]
1
A statement can be labeled.
labeled-statement:
attribute-specifier-seqopt identifier : statement
attribute-specifier-seqopt case constant-expression : statement
attribute-specifier-seqopt default : statement
§ 9.1
130
The optional attribute-specifier-seq appertains to the label. An identifier label declares the identifier. The
only use of an identifier label is as the target of a goto. The scope of a label is the function in which it
appears. Labels shall not be redeclared within a function. A label can be used in a goto statement before its
declaration. Labels have their own name space and do not interfere with other identifiers. [Note: A label
may have the same name as another declaration in the same scope or a template-parameter from an enclosing
scope. Unqualified name lookup (6.4.1) ignores labels.
— end note ]
2
Case labels and default labels shall occur only in switch statements.
9.2
Expression statement
[stmt.expr]
1
Expression statements have the form
expression-statement:
expressionopt ;
The expression is a discarded-value expression (8.2). All side effects from an expression statement are
completed before the next statement is executed. An expression statement with the expression missing is
called a null statement. [ Note: Most statements are expression statements — usually assignments or function
calls. A null statement is useful to carry a label just before the } of a compound statement and to supply a
null body to an iteration statement such as a while statement (9.5.1).
— end note ]
9.3
Compound statement or block
[stmt.block]
1
So that several statements can be used where one is expected, the compound statement (also, and equivalently,
called “block”) is provided.
compound-statement:
{ statement-seqopt }
statement-seq:
statement
statement-seq statement
A compound statement defines a block scope (6.3). [ Note: A declaration is a statement (9.7).
— end note ]
9.4
Selection statements
[stmt.select]
1
Selection statements choose one of several flows of control.
selection-statement:
if constexpropt ( init-statementopt condition ) statement
if constexpropt ( init-statementopt condition ) statement else statement
switch ( init-statementopt condition ) statement
See 11.3 for the optional attribute-specifier-seq in a condition. [ Note: An init-statement ends with a semicolon.
— end note ] In Clause 9, the term substatement refers to the contained statement or statements that appear
in the syntax notation. The substatement in a selection-statement (each substatement, in the else form
of the if statement) implicitly defines a block scope (6.3). If the substatement in a selection-statement is
a single statement and not a compound-statement, it is as if it was rewritten to be a compound-statement
containing the original substatement. [ Example:
if (x)
int i;
can be equivalently rewritten as
if (x) {
int i;
}
Thus after the if statement, i is no longer in scope.
— end example ]
9.4.1
The if statement
[stmt.if]
1
If the condition (9.4) yields true the first substatement is executed. If the else part of the selection statement
is present and the condition yields false, the second substatement is executed. If the first substatement
is reached via a label, the condition is not evaluated and the second substatement is not executed. In the
second form of if statement (the one including else), if the first substatement is also an if statement then
that inner if statement shall contain an else part.92
92) In other words, the else is associated with the nearest un-elsed if.
§ 9.4.1
131
2
If the if statement is of the form if constexpr, the value of the condition shall be a contextually converted
constant expression of type bool (8.6); this form is called a constexpr if statement. If the value of the converted
condition is false, the first substatement is a discarded statement, otherwise the second substatement, if
present, is a discarded statement. During the instantiation of an enclosing templated entity (Clause 17),
if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not
instantiated. [ Note: Odr-uses (6.2) in a discarded statement do not require an entity to be defined.
— end
note ] A case or default label appearing within such an if statement shall be associated with a switch
statement (9.4.2) within the same if statement. A label (9.1) declared in a substatement of a constexpr if
statement shall only be referred to by a statement (9.6.4) in the same substatement. [ Example:
template<typename T, typename ... Rest> void g(T&& p, Rest&& ...rs)
{
// ... handle p
if constexpr (sizeof...(rs) > 0)
g(rs...);
// never instantiated with an empty argument list
}
extern int x;
// no definition of x required
int f() {
if constexpr (true)
return 0;
else if (x)
return x;
else
return -x;
}
— end example ]
3
An if statement of the form
if constexpropt ( init-statement condition ) statement
is equivalent to
{
init-statement
if constexpropt ( condition ) statement
}
and an if statement of the form
if constexpropt ( init-statement condition ) statement else statement
is equivalent to
{
init-statement
if constexpropt ( condition ) statement else statement
}
except that names declared in the init-statement are in the same declarative region as those declared in the
condition.
9.4.2
The switch statement
[stmt.switch]
1
The switch statement causes control to be transferred to one of several statements depending on the value
of a condition.
2
The condition shall be of integral type, enumeration type, or class type. If of class type, the condition is
contextually implicitly converted (Clause 7) to an integral or enumeration type. If the (possibly converted)
type is subject to integral promotions (7.6), the condition is converted to the promoted type. Any statement
within the switch statement can be labeled with one or more case labels as follows:
case constant-expression :
where the constant-expression shall be a converted constant expression (8.6) of the adjusted type of the
switch condition. No two of the case constants in the same switch shall have the same value after conversion.
3
There shall be at most one label of the form
§ 9.4.2
132
default :
within a switch statement.
4
Switch statements can be nested; a case or default label is associated with the smallest switch enclosing it.
5
When the switch statement is executed, its condition is evaluated and compared with each case constant. If
one of the case constants is equal to the value of the condition, control is passed to the statement following
the matched case label. If no case constant matches the condition, and if there is a default label, control
passes to the statement labeled by the default label. If no case matches and if there is no default then none
of the statements in the switch is executed.
6
case and default labels in themselves do not alter the flow of control, which continues unimpeded across
such labels. To exit from a switch, see break, 9.6.1. [ Note: Usually, the substatement that is the subject of
a switch is compound and case and default labels appear on the top-level statements contained within the
(compound) substatement, but this is not required. Declarations can appear in the substatement of a switch
statement.
— end note ]
7
A switch statement of the form
switch ( init-statement condition ) statement
is equivalent to
{
init-statement
switch ( condition ) statement
}
except that names declared in the init-statement are in the same declarative region as those declared in the
condition.
9.5
Iteration statements
[stmt.iter]
1
Iteration statements specify looping.
iteration-statement:
while ( condition ) statement
do statement while ( expression ) ;
for ( init-statement conditionopt ; expressionopt ) statement
for ( init-statementopt for-range-declaration : for-range-initializer ) statement
for-range-declaration:
attribute-specifier-seqopt decl-specifier-seq declarator
attribute-specifier-seqopt decl-specifier-seq ref-qualifieropt [ identifier-list ]
for-range-initializer:
expr-or-braced-init-list
See 11.3 for the optional attribute-specifier-seq in a for-range-declaration. [ Note: An init-statement ends
with a semicolon.
— end note ]
2
The substatement in an iteration-statement implicitly defines a block scope (6.3) which is entered and exited
each time through the loop.
If the substatement in an iteration-statement is a single statement and not a compound-statement, it is as if
it was rewritten to be a compound-statement containing the original statement. [ Example:
while (--x >= 0)
int i;
can be equivalently rewritten as
while (--x >= 0) {
int i;
}
Thus after the while statement, i is no longer in scope.
— end example ]
3
If a name introduced in an init-statement or for-range-declaration is redeclared in the outermost block of the
substatement, the program is ill-formed. [ Example:
void f() {
for (int i = 0; i < 10; ++i)
int i = 0;
// error: redeclaration
§ 9.5
133
for (int i : { 1, 2, 3 })
int i = 1;
// error: redeclaration
}
— end example ]
9.5.1
The while statement
[stmt.while]
1
In the while statement the substatement is executed repeatedly until the value of the condition (9.4) becomes
false. The test takes place before each execution of the substatement.
2
When the condition of a while statement is a declaration, the scope of the variable that is declared extends
from its point of declaration (6.3.2) to the end of the while statement. A while statement of the form
while (T t = x) statement
is equivalent to
label:
{
// start of condition scope
T t = x;
if (t) {
statement
goto label;
}
}
// end of condition scope
The variable created in a condition is destroyed and created with each iteration of the loop. [ Example:
struct A {
int val;
A(int i) : val(i) { }
~A() { }
operator bool() { return val != 0; }
};
int i = 1;
while (A a = i) {
// ...
i = 0;
}
In the while-loop, the constructor and destructor are each called twice, once for the condition that succeeds
and once for the condition that fails.
— end example ]
9.5.2
The do statement
[stmt.do]
1
The expression is contextually converted to bool (Clause 7); if that conversion is ill-formed, the program is
ill-formed.
2
In the do statement the substatement is executed repeatedly until the value of the expression becomes false.
The test takes place after each execution of the statement.
9.5.3
The for statement
[stmt.for]
1
The for statement
for ( init-statement conditionopt ; expressionopt ) statement
is equivalent to
{
init-statement
while ( condition ) {
statement
expression ;
}
}
except that names declared in the init-statement are in the same declarative region as those declared in
the condition, and except that a continue in statement (not enclosed in another iteration statement) will
execute expression before re-evaluating condition. [ Note: Thus the first statement specifies initialization for
the loop; the condition (9.4) specifies a test, sequenced before each iteration, such that the loop is exited
§ 9.5.3
134
when the condition becomes false; the expression often specifies incrementing that is sequenced after each
iteration.
— end note ]
2
Either or both of the condition and the expression can be omitted. A missing condition makes the implied
while clause equivalent to while(true).
3
If the init-statement is a declaration, the scope of the name(s) declared extends to the end of the for
statement. [ Example:
int i = 42;
int a[10];
for (int i = 0; i < 10; i++)
a[i] = i;
int j = i;
// j = 42
— end example ]
9.5.4
The range-based for statement
[stmt.ranged]
1
The range-based for statement
for ( init-statementopt for-range-declaration : for-range-initializer ) statement
is equivalent to
{
init-statementopt
auto &&__range = for-range-initializer ;
auto __begin = begin-expr ;
auto __end = end-expr ;
for ( ; __begin != __end; ++__begin ) {
for-range-declaration = *__begin;
statement
}
}
where
(1.1)
—
if the for-range-initializer is an expression, it is regarded as if it were surrounded by parentheses (so
that a comma operator cannot be reinterpreted as delimiting two init-declarator s);
(1.2)
—
__range, __begin, and __end are variables defined for exposition only; and
(1.3)
—
begin-expr and end-expr are determined as follows:
(1.3.1)
—
if the for-range-initializer is an expression of array type R, begin-expr and end-expr are __range
and __range + __bound, respectively, where __bound is the array bound. If R is an array of
unknown bound or an array of incomplete type, the program is ill-formed;
(1.3.2)
—
if the for-range-initializer is an expression of class type C, the unqualified-ids begin and end are
looked up in the scope of C as if by class member access lookup (6.4.5), and if either (or both)
finds at least one declaration, begin-expr and end-expr are __range.begin() and __range.end(),
respectively;
(1.3.3)
—
otherwise, begin-expr and end-expr are begin(__range) and end(__range), respectively, where
begin and end are looked up in the associated namespaces (6.4.2). [ Note: Ordinary unqualified
lookup (6.4.1) is not performed.
— end note ]
[ Example:
int array[5] = { 1, 2, 3, 4, 5 };
for (int& x : array)
x *= 2;
— end example ]
2
In the decl-specifier-seq of a for-range-declaration, each decl-specifier shall be either a type-specifier or
constexpr. The decl-specifier-seq shall not define a class or enumeration.
9.6
Jump statements
[stmt.jump]
1
Jump statements unconditionally transfer control.
§ 9.6
135
jump-statement:
break ;
continue ;
return expr-or-braced-init-listopt ;
goto identifier ;
2
On exit from a scope (however accomplished), objects with automatic storage duration (6.6.4.3) that have
been constructed in that scope are destroyed in the reverse order of their construction. [ Note: For temporaries,
see 15.2.
— end note ] Transfer out of a loop, out of a block, or back past an initialized variable with
automatic storage duration involves the destruction of objects with automatic storage duration that are in
scope at the point transferred from but not at the point transferred to. (See 9.7 for transfers into blocks).
[Note: However, the program can be terminated (by calling std::exit() or std::abort() (21.5), for
example) without destroying class objects with automatic storage duration.
— end note ]
9.6.1
The break statement
[stmt.break]
1
The break statement shall occur only in an iteration-statement or a switch statement and causes termination
of the smallest enclosing iteration-statement or switch statement; control passes to the statement following
the terminated statement, if any.
9.6.2
The continue statement
[stmt.cont]
1
The continue statement shall occur only in an iteration-statement and causes control to pass to the loop-
continuation portion of the smallest enclosing iteration-statement, that is, to the end of the loop. More
precisely, in each of the statements
while (foo) {
do {
for (;;) {
{
{
{
// ...
// ...
// ...
}
}
}
contin: ;
contin: ;
contin: ;
}
} while (foo);
}
a continue not contained in an enclosed iteration statement is equivalent to goto contin.
9.6.3
The return statement
[stmt.return]
1
A function returns to its caller by the return statement.
2
The expr-or-braced-init-list of a return statement is called its operand. A return statement with no operand
shall be used only in a function whose return type is cv void, a constructor (15.1), or a destructor (15.4). A
return statement with an operand of type void shall be used only in a function whose return type is cv void.
A return statement with any other operand shall be used only in a function whose return type is not cv void;
the return statement initializes the glvalue result or prvalue result object of the (explicit or implicit) function
call by copy-initialization (11.6) from the operand. [ Note: A return statement can involve an invocation of a
constructor to perform a copy or move of the operand if it is not a prvalue or if its type differs from the return
type of the function. A copy operation associated with a return statement may be elided or converted to a
move operation if an automatic storage duration variable is returned (15.8).
— end note ] [ Example:
std::pair<std::string,int> f(const char* p, int x) {
return {p,x};
}
— end example ] Flowing off the end of a constructor, a destructor, or a function with a cv void return
type is equivalent to a return with no operand. Otherwise, flowing off the end of a function other than
main (6.8.3.1) results in undefined behavior.
3
The copy-initialization of the result of the call is sequenced before the destruction of temporaries at the end
of the full-expression established by the operand of the return statement, which, in turn, is sequenced before
the destruction of local variables (9.6) of the block enclosing the return statement.
9.6.4
The goto statement
[stmt.goto]
1
The goto statement unconditionally transfers control to the statement labeled by the identifier. The identifier
shall be a label (9.1) located in the current function.
§ 9.6.4
136
9.7
Declaration statement
[stmt.dcl]
1
A declaration statement introduces one or more new identifiers into a block; it has the form
declaration-statement:
block-declaration
If an identifier introduced by a declaration was previously declared in an outer block, the outer declaration is
hidden for the remainder of the block, after which it resumes its force.
2
Variables with automatic storage duration (6.6.4.3) are initialized each time their declaration-statement is
executed. Variables with automatic storage duration declared in the block are destroyed on exit from the
block (9.6).
3
It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A
program that jumps93 from a point where a variable with automatic storage duration is not in scope to a
point where it is in scope is ill-formed unless the variable has scalar type, class type with a trivial default
constructor and a trivial destructor, a cv-qualified version of one of these types, or an array of one of the
preceding types and is declared without an initializer (11.6). [ Example:
void f() {
// ...
goto lx;
// ill-formed: jump into scope of a
// ...
ly:
X a = 1;
// ...
lx:
goto ly;
// OK, jump implies destructor call for a followed by
// construction again immediately following label ly
}
— end example ]
4
Dynamic initialization of a block-scope variable with static storage duration (6.6.4.1) or thread storage
duration (6.6.4.2) is performed the first time control passes through its declaration; such a variable is
considered initialized upon the completion of its initialization. If the initialization exits by throwing an
exception, the initialization is not complete, so it will be tried again the next time control enters the declaration.
If control enters the declaration concurrently while the variable is being initialized, the concurrent execution
shall wait for completion of the initialization.94
If control re-enters the declaration recursively while the
variable is being initialized, the behavior is undefined. [ Example:
int foo(int i) {
static int s = foo(2*i);
// recursive call - undefined
return i+1;
}
— end example ]
5
The destructor for a block-scope object with static or thread storage duration will be executed if and only if
it was constructed. [Note: 6.8.3.4 describes the order in which block-scope objects with static and thread
storage duration are destroyed.
— end note ]
9.8
Ambiguity resolution
[stmt.ambig]
1
There is an ambiguity in the grammar involving expression-statements and declarations: An expression-
statement with a function-style explicit type conversion (8.5.1.3) as its leftmost subexpression can be
indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is
a declaration.
2
[Note: If the statement cannot syntactically be a declaration, there is no ambiguity, so this rule does not
apply. The whole statement might need to be examined to determine whether this is the case. This resolves
the meaning of many examples. [ Example: Assuming T is a simple-type-specifier (10.1.7),
T(a)->m = 7;
// expression-statement
T(a)++;
// expression-statement
T(a,5)<<c;
// expression-statement
93) The transfer from the condition of a switch statement to a case label is considered a jump in this respect.
94) The implementation must not introduce any deadlock around execution of the initializer. Deadlocks might still be caused
by the program logic; the implementation need only avoid deadlocks due to its own synchronization operations.
§ 9.8
137
T(*d)(int);
// declaration
T(e)[5];
// declaration
T(f) = { 1, 2 };
// declaration
T(*g)(double(3));
// declaration
In the last example above, g, which is a pointer to T, is initialized to double(3). This is of course ill-formed
for semantic reasons, but that does not affect the syntactic analysis.
— end example ]
The remaining cases are declarations. [ Example:
class T {
// ...
public:
T();
T(int);
T(int, int);
};
T(a);
// declaration
T(*b)();
// declaration
T(c)=7;
// declaration
T(d),e,f=3;
// declaration
extern int h;
T(g)(h,2);
// declaration
— end example ]
— end note ]
3
The disambiguation is purely syntactic; that is, the meaning of the names occurring in such a statement,
beyond whether they are type-names or not, is not generally used in or changed by the disambiguation. Class
templates are instantiated as necessary to determine if a qualified name is a type-name. Disambiguation
precedes parsing, and a statement disambiguated as a declaration may be an ill-formed declaration. If, during
parsing, a name in a template parameter is bound differently than it would be bound during a trial parse,
the program is ill-formed. No diagnostic is required. [ Note: This can occur only when the name is declared
earlier in the declaration.
— end note ] [ Example:
struct T1 {
T1 operator()(int x) { return T1(x); }
int operator=(int x) { return x; }
T1(int) { }
};
struct T2 { T2(int){ } };
int a, (*(*b)(T2))(int), c, d;
void f() {
// disambiguation requires this to be parsed as a declaration:
T1(a) = 3,
T2(4),
// T2 will be declared as a variable of type T1, but this will not
(*(*b)(T2(c)))(int(d));
// allow the last part of the declaration to parse properly,
// since it depends on T2 being a type-name
}
— end example ]
§ 9.8
138
10
Declarations
[dcl.dcl]
1
Declarations generally specify how names are to be interpreted. Declarations have the form
declaration-seq:
declaration
declaration-seq declaration
declaration:
block-declaration
nodeclspec-function-declaration
function-definition
template-declaration
deduction-guide
explicit-instantiation
explicit-specialization
linkage-specification
namespace-definition
empty-declaration
attribute-declaration
block-declaration:
simple-declaration
asm-definition
namespace-alias-definition
using-declaration
using-directive
static_assert-declaration
alias-declaration
opaque-enum-declaration
nodeclspec-function-declaration:
attribute-specifier-seqopt declarator ;
alias-declaration:
using identifier attribute-specifier-seqopt
= defining-type-id ;
simple-declaration:
decl-specifier-seq init-declarator-listopt ;
attribute-specifier-seq decl-specifier-seq init-declarator-list ;
attribute-specifier-seqopt decl-specifier-seq ref-qualifieropt [ identifier-list ] initializer ;
static_assert-declaration:
static_assert ( constant-expression ) ;
static_assert ( constant-expression , string-literal ) ;
empty-declaration:
;
attribute-declaration:
attribute-specifier-seq ;
[Note: asm-definitions are described in 10.4, and linkage-specifications are described in
10.5.
Function-
definitions are described in 11.4 and template-declarations and deduction-guides are described in Clause 17.
Namespace-definitions are described in 10.3.1, using-declarations are described in 10.3.3 and using-directives
are described in 10.3.4.
— end note ]
2
A simple-declaration or nodeclspec-function-declaration of the form
attribute-specifier-seqopt decl-specifier-seqopt init-declarator-listopt ;
is divided into three parts. Attributes are described in 10.6. decl-specifiers, the principal components of a
decl-specifier-seq, are described in 10.1. declarator s, the components of an init-declarator-list, are described in
Clause 11. The attribute-specifier-seq appertains to each of the entities declared by the declarators of the
init-declarator-list. [ Note: In the declaration for an entity, attributes appertaining to that entity may appear
at the start of the declaration and after the declarator-id for that declaration.
— end note ] [ Example:
Declarations
139
[[noreturn]] void f [[noreturn]] ();
// OK
— end example ]
3
Except where otherwise specified, the meaning of an attribute-declaration is implementation-defined.
4
A declaration occurs in a scope (6.3); the scope rules are summarized in 6.4. A declaration that declares a
function or defines a class, namespace, template, or function also has one or more scopes nested within it.
These nested scopes, in turn, can have declarations nested within them. Unless otherwise stated, utterances
in Clause 10 about components in, of, or contained by a declaration or subcomponent thereof refer only to
those components of the declaration that are not nested within scopes nested within the declaration.
5
In a simple-declaration, the optional init-declarator-list can be omitted only when declaring a class (Clause
12) or enumeration (10.2), that is, when the decl-specifier-seq contains either a class-specifier, an elaborated-
type-specifier with a class-key (12.1), or an enum-specifier. In these cases and whenever a class-specifier or
enum-specifier is present in the decl-specifier-seq, the identifiers in these specifiers are among the names being
declared by the declaration (as class-names, enum-names, or enumerators, depending on the syntax). In
such cases, the decl-specifier-seq shall introduce one or more names into the program, or shall redeclare a
name introduced by a previous declaration. [ Example:
enum { };
// ill-formed
typedef class { };
// ill-formed
— end example ]
6
In a static_assert-declaration, the constant-expression shall be a contextually converted constant expression
of type bool (8.6). If the value of the expression when so converted is true, the declaration has no effect.
Otherwise, the program is ill-formed, and the resulting diagnostic message (4.1) shall include the text of
the string-literal, if one is supplied, except that characters not in the basic source character set (5.3) are not
required to appear in the diagnostic message. [ Example:
static_assert(char(-1) < 0, "this library requires plain ’char’ to be signed");
— end example ]
7
An empty-declaration has no effect.
8
A simple-declaration with an identifier-list is called a structured binding declaration (11.5). The decl-specifier-
seq shall contain only the type-specifier auto (10.1.7.4) and cv-qualifier s. The initializer shall be of the form
“= assignment-expression”, of the form “{ assignment-expression }”, or of the form “( assignment-expression
)”, where the assignment-expression is of array or non-union class type.
9
Each init-declarator in the init-declarator-list contains exactly one declarator-id, which is the name declared
by that init-declarator and hence one of the names declared by the declaration. The defining-type-specifier s
(10.1.7) in the decl-specifier-seq and the recursive declarator structure of the init-declarator describe a
type (11.3), which is then associated with the name being declared by the init-declarator.
10
If the decl-specifier-seq contains the typedef specifier, the declaration is called a typedef declaration and the
name of each init-declarator is declared to be a typedef-name, synonymous with its associated type (10.1.3).
If the decl-specifier-seq contains no typedef specifier, the declaration is called a function declaration if the
type associated with the name is a function type (11.3.5) and an object declaration otherwise.
11
Syntactic components beyond those found in the general form of declaration are added to a function declaration
to make a function-definition. An object declaration, however, is also a definition unless it contains the
extern specifier and has no initializer (6.1). A definition causes the appropriate amount of storage to be
reserved and any appropriate initialization (11.6) to be done.
12
A nodeclspec-function-declaration shall declare a constructor, destructor, or conversion function.95 [ Note: A
nodeclspec-function-declaration can only be used in a template-declaration (Clause 17), explicit-instantiation
(17.8.2), or explicit-specialization (17.8.3).
— end note ]
10.1
Specifiers
[dcl.spec]
1
The specifiers that can be used in a declaration are
95) The “implicit int” rule of C is no longer supported.
§ 10.1
140
decl-specifier:
storage-class-specifier
defining-type-specifier
function-specifier
friend
typedef
constexpr
inline
decl-specifier-seq:
decl-specifier attribute-specifier-seqopt
decl-specifier decl-specifier-seq
The optional attribute-specifier-seq in a decl-specifier-seq appertains to the type determined by the preceding
decl-specifier s (11.3). The attribute-specifier-seq affects the type only for the declaration it appears in, not
other declarations involving the same type.
2
Each decl-specifier shall appear at most once in a complete decl-specifier-seq, except that long may appear
twice.
3
If a type-name is encountered while parsing a decl-specifier-seq, it is interpreted as part of the decl-specifier-seq
if and only if there is no previous defining-type-specifier other than a cv-qualifier in the decl-specifier-seq.
The sequence shall be self-consistent as described below. [ Example:
typedef char* Pc;
static Pc;
// error: name missing
Here, the declaration static Pc is ill-formed because no name was specified for the static variable of type Pc.
To get a variable called Pc, a type-specifier (other than const or volatile) has to be present to indicate
that the typedef-name Pc is the name being (re)declared, rather than being part of the decl-specifier sequence.
For another example,
void f(const Pc);
// void f(char* const) (not const char*)
void g(const int Pc);
// void g(const int)
— end example ]
4
[ Note: Since signed, unsigned, long, and short by default imply int, a type-name appearing after one of
those specifiers is treated as the name being (re)declared. [ Example:
void h(unsigned Pc);
// void h(unsigned int)
void k(unsigned int Pc);
// void k(unsigned int)
— end example ]
— end note ]
10.1.1
Storage class specifiers
[dcl.stc]
1
The storage class specifiers are
storage-class-specifier:
static
thread_local
extern
mutable
At most one storage-class-specifier shall appear in a given decl-specifier-seq, except that thread_local may
appear with static or extern. If thread_local appears in any declaration of a variable it shall be present
in all declarations of that entity. If a storage-class-specifier appears in a decl-specifier-seq, there can be
no typedef specifier in the same decl-specifier-seq and the init-declarator-list or member-declarator-list of
the declaration shall not be empty (except for an anonymous union declared in a named namespace or
in the global namespace, which shall be declared static (12.3.1)). The storage-class-specifier applies to
the name declared by each init-declarator in the list and not to any names declared by other specifiers. A
storage-class-specifier other than thread_local shall not be specified in an explicit specialization (17.8.3) or
an explicit instantiation (17.8.2) directive.
2
[ Note: A variable declared without a storage-class-specifier at block scope or declared as a function parameter
has automatic storage duration by default (6.6.4.3).
— end note ]
3
The thread_local specifier indicates that the named entity has thread storage duration (6.6.4.2). It shall be
applied only to the names of variables of namespace or block scope and to the names of static data members.
§ 10.1.1
141
|
|