If the operand points to an object or function,
the result denotes that object or function;
otherwise, the behavior is undefined except as specified in [expr.typeid].
Indirection through a pointer to an incomplete type (other than
cvvoid) is valid.
The lvalue thus obtained can be
used in limited ways (to initialize a reference, for example); this
lvalue must not be converted to a prvalue, see [conv.lval].
If the operand is a qualified-id or splice-expression
designating a non-static member m,
other than an explicit object member function,
m shall be a direct member of some class C
that is not an anonymous union.
The result has type “pointer to member of class C of type T”
and designates C::m.
A qualified-id
that names a member of a namespace-scope anonymous union
is considered to be a class member access expression ([expr.prim.id.general])
and cannot be used to form a pointer to member.
In particular, taking the address of a variable of type “cvT”
yields a pointer of type “pointer to cvT”.
— end note]
[Example 1: struct A {int i; };
struct B : A {};
..&B::i ../ has type int A::*int a;
int* p1 =&a;
int* p2 = p1 +1; / defined behaviorbool b = p2 > p1; / defined behavior, with value true — end example]
A pointer to member formed from a mutable non-static data
member ([dcl.stc]) does not reflect the mutable specifier
associated with the non-static data member.
That is, the expression &(qualified-id), where the
qualified-id is enclosed in parentheses, does not form an
expression of type “pointer to member”.
Neither does
qualified-id, because there is no implicit conversion from a
qualified-id for a non-static member function to the type
“pointer to member function” as there is from an lvalue of function
type to the type “pointer to function” ([conv.func]).
Nor is
&unqualified-id a pointer to member, even within the scope of
the unqualified-id's class.
If & is applied to an lvalue of incomplete class type and the
complete type declares operator&(), it is unspecified whether
the operator has the built-in meaning or the operator function is
called.
The address of an overload set ([over]) can be taken
only in a context that uniquely determines
which function is referred to (see [over.over]).
Since the context can affect whether the operand is a static or
non-static member function, the context can also affect whether the
expression has type “pointer to function” or “pointer to member
function”.
The operand of the unary + operator shall be a prvalue of
arithmetic, unscoped
enumeration, or pointer type and the result is the value of the
argument.
Integral promotion is performed on integral or enumeration
operands.
The type of the result is the type of the promoted operand.
The operand of the logical negation operator ! is contextually
converted to bool ([conv]);
its value is true
if the converted operand is false and false otherwise.
The type of the result is the type of the promoted operand.
Given the coefficients xi
of the base-2 representation ([basic.fundamental])
of the promoted operand x,
the coefficient ri
of the base-2 representation of the result r
is 1 if xi is 0, and 0 otherwise.
Because the grammar does not permit an operator to follow the
., ->, or :: tokens, a ~ followed by
a type-name or computed-type-specifier in a
member access expression or qualified-id is
unambiguously parsed as a destructor name.
The co_await expression is used to suspend evaluation of a
coroutine ([dcl.fct.def.coroutine]) while awaiting completion of
the computation represented by the operand expression.
Suspending the evaluation of a coroutine
transfers control to its caller or resumer.
o is determined by enumerating the applicable
operatorco_await functions for an argument
a ([over.match.oper]), and choosing the best one through
overload resolution ([over.match]).
If overload resolution is ambiguous,
the program is ill-formed.
This resumes the coroutine referred to
by the result of await-suspend.
Any number of coroutines can be successively resumed in this fashion,
eventually returning control flow to the current coroutine caller or
resumer ([dcl.fct.def.coroutine]).
If the evaluation of await-suspend
exits via an exception, the exception is caught,
the coroutine is resumed, and the exception is immediately
rethrown ([except.throw]).
Otherwise, control flow returns
to the current coroutine caller or resumer ([dcl.fct.def.coroutine])
without exiting any scopes ([stmt.jump]).
The point in the coroutine
immediately prior to control returning to its caller or resumer
is a coroutine suspend point.
If the result of await-ready is true,
or when the coroutine is resumed
other than by rethrowing an exception from await-suspend,
the await-resume expression is evaluated, and
its result is the result of the await-expression.
The sizeof operator shall not be applied to an expression that
has function or incomplete type,
to the parenthesized name of such
types, or to a glvalue that designates a bit-field.
The result of sizeof
applied to any of the narrow character types is 1.
The result of
sizeof applied to any other fundamental
type ([basic.fundamental]) is implementation-defined.
When applied to a reference type, the result is the size
of the referenced type.
When applied to a class, the result is the number of bytes in an object
of that class including any padding required for placing objects of that
type in an array.
The result of applying sizeof to a
potentially-overlapping subobject is
the size of the type, not the size of the subobject.54
When applied to an array, the result is the total number of bytes in the
array.
This implies that the size of an array of n elements is
n times the size of an element.
The lvalue-to-rvalue ([conv.lval]),
array-to-pointer ([conv.array]), and
function-to-pointer ([conv.func]) standard conversions are not
applied to the operand of sizeof.
The actual size of a potentially-overlapping subobject
can be less than the result of
applying sizeof to the subobject, due to virtual base classes
and less strict padding requirements on potentially-overlapping subobjects.
[Example 1: newauto(1); / allocated type is intauto x =newauto('a'); / allocated type is char, x is of type char*template<class T>struct A { A(T, T); };
auto y =new A{1, 2}; / allocated type is A<int> — end example]
Given the definition int n =42,
newfloat[n][5] is well-formed (because n is the
expression of a noptr-new-declarator), but
newfloat[5][n] is ill-formed (because n is not a
constant expression).
Furthermore,
newfloat[0] is well-formed
(because 0 is the expression
of a noptr-new-declarator,
where a value of zero results in the allocation of an array with no elements),
but newfloat[n][0] is ill-formed
(because 0 is the constant-expression
of a noptr-new-declarator,
where only values greater than zero are allowed).
if the allocation function that would have been called
has a non-throwing exception specification ([except.spec]),
the value of the new-expression
is the null pointer value of the required result type;
If the allocated type is an array,
the new-initializer is a braced-init-list
or a parenthesized expression-list, and
the expression
is potentially-evaluated and not a core constant expression,
the semantic constraints of initializing a hypothetical element of
the array are checked as follows:
The array can contain more elements than there are
elements in the new-initializer,
requiring initialization of the remainder of the array elements as appropriate.
When the allocated type is “array of NT”
(that is, the noptr-new-declarator syntax is used or the
new-type-id or type-id denotes an array type),
the new-expression yields a prvalue of type “pointer to T”
that points to the initial element (if any) of the array.
Otherwise, let T be the allocated type;
the new-expression
is a prvalue of type “pointer to T”
that points to the object created.
The set of allocation and deallocation functions that can be called
by a new-expression
can include functions that do not perform allocation or deallocation;
for example, see [new.delete.placement].
If the new-expression
does not begin with a unary :: operator and
the allocated type is a class type T or array thereof,
a search is performed for the allocation function's name in the scope
of T ([class.member.lookup]).
Otherwise, or if nothing is found,
the allocation function's name is looked up by
searching for it in the global scope.
The implementation may
extend the allocation of a new-expressione1 to provide
storage for a new-expressione2 if the
following would be true were the allocation not extended:
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
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 and
the allocation function is not a non-allocating form ([new.delete.placement]).
For arrays of
char, unsignedchar, 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 of any object type whose size
is no greater than the size of the array being created.
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.
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.
otherwise, an argument that
is the type's alignment and has type std::align_val_t
is added into the argument list immediately after the first argument;
new(2,f) T[5] results in one of the following calls:
operatornew[](sizeof(T)*5+ x, 2, f)operatornew[](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 operatornew[].
This overhead may be applied in all
array new-expressions, including those referencing
a placement allocation function, except when referencing
the library function operatornew[](std::size_t, void*).
The amount of overhead may vary from one
invocation of new to another.
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 ([new.delete.placement]) 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.
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 ([basic.align])
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.
If any part of the object initialization described above56
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.
If the new-expression does not begin with
a unary :: operator and
the allocated type is a class type T or an array thereof,
a search is performed for the deallocation function's name
in the scope of T.
Otherwise, or if nothing is found,
the deallocation function's name is looked up by
searching for it in the global scope.
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 ([dcl.fct]), 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
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 ([expr.delete]).
In any case,
the matching deallocation function (if any) shall be non-deleted and
accessible from the point where the new-expression appears.
[Example 7: struct S {/ Placement allocation function:staticvoid*operatornew(std::size_t, std::size_t);
/ Usual (non-placement) deallocation function:staticvoidoperatordelete(void*, std::size_t);
};
S* p =new(0) S; / error: non-placement deallocation function matches/ placement allocation function — end example]
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 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.
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.
Whenever the delete keyword is immediately followed by empty square
brackets, it shall be interpreted as the second alternative.57
If the operand is of
class type, it is contextually implicitly converted ([conv])
to a pointer to object
type
and the converted operand is used in place of the original operand
for the remainder of this subclause.
Otherwise, it shall be a prvalue of pointer to object type.
In a single-object delete expression, the value of the operand of
delete may be a null pointer value,
a pointer value
that resulted from a previous non-array new-expression, or
a pointer to a base class subobject
of an object created by such a new-expression.
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 whose
allocation function was not a non-allocating form ([new.delete.placement]).58
A pointer to a const type can be the operand of a
delete-expression; it is not necessary to cast away the
constness ([expr.const.cast]) of the pointer expression before it is
used as the operand of the delete-expression.
In a single-object delete expression, if the static type of the object to be
deleted is not similar ([conv.qual]) to its dynamic type
and the selected deallocation function (see below)
is not a destroying operator delete,
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 is not similar to
its static type, the behavior is undefined.
If the value of the operand of the delete-expression is not a
null pointer value
and the selected deallocation function (see below)
is not a destroying operator delete,
evaluating the delete-expression invokes the
destructor (if any) for the object or the elements of the array being
deleted.
The destructor shall be accessible from the point where
the delete-expression appears.
In the case of an array, the elements are destroyed in
order of decreasing address (that is, in reverse order of the completion
of their constructor; see [class.base.init]).
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.
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.
If the keyword delete in a delete-expression
is not preceded by the unary :: operator and the type of the operand is
a pointer to a (possibly cv-qualified) class type T
or (possibly multidimensional) array thereof:
For a single-object delete expression,
if the operand is a pointer to cvT and
T has a virtual destructor,
the deallocation function is the one selected at the point of definition of
the dynamic type's virtual destructor ([class.dtor]).
If any of the deallocation functions is a destroying operator delete,
all deallocation functions that are not destroying operator deletes
are eliminated from further consideration.
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 any preferred functions are found,
all non-preferred functions are eliminated from further consideration.
If the type is complete
and if, for an array delete expression only,
the operand is a pointer to a class type with a
non-trivial destructor or a (possibly multidimensional) array thereof,
the function with a parameter of type std::size_t is selected.
Otherwise, it is unspecified
whether a deallocation function with a parameter of type std::size_t
is selected.
Unless the deallocation function is selected
at the point of definition of the dynamic type's virtual destructor,
the selected deallocation function shall be accessible
from the point where the delete-expression appears.
For a single-object delete expression,
the deleted object is
the object A pointed to by the operand
if the static type of A does not have a virtual destructor,
and the most-derived object of A otherwise.
If the deallocation function is not a destroying operator delete
and the deleted object is not the most derived object in the former case,
the behavior is undefined,
as stated above.
— end note]
For an array delete expression,
the deleted object is
the array object.
When a delete-expression
is executed, the selected deallocation function shall be called with
the address of the deleted object
in a single-object delete expression, or
the address of the deleted object
suitably adjusted for the array allocation
overhead ([expr.new]) in an array delete expression,
as its first argument.
Any cv-qualifiers in the type of the deleted object
are ignored when forming this argument.
— end note]
If a destroying operator delete is used,
an unspecified value
is passed as the argument
corresponding to the parameter of type std::destroying_delete_t.
If a deallocation function
with a parameter of type std::align_val_t
is used,
the alignment of the type of the deleted object
is passed as the corresponding argument.
If a deallocation function
with a parameter of type std::size_t is used,
the size of the deleted object
in a single-object delete expression, or
of the array plus allocation overhead
in an array delete expression,
is passed as the corresponding argument.
If this results in a call to a replaceable deallocation function,
and either
the first argument was not the result of
a prior call to a replaceable allocation function or
the second or third argument was not the corresponding argument in said call,
the behavior is undefined ([new.delete.single], [new.delete.array]).
This document places no restriction on representing, by reflections,
constructs not described by this document or
using the names of such constructs
as operands of reflect-expressions.
An unparenthesized reflect-expression
that represents a template shall not be followed by <.
[Example 1: static_assert(std::meta::is_type(^int(); / ^^ applies to the type-id int()template<bool>struct X {};
constevalbooloperator<(std::meta::info, X<false>){returnfalse; }constevalvoid g(std::meta::info r, X<false> xv){
r ==^^int&&true; / error: ^^ applies to the type-idint&&
r ==^^int&true; / error: ^^ applies to the type-id int&
r ==(^int)&&true; / OK
r ==^^int&&true; / error: int &&&& is not a valid type-id^^X < xv; / error: reflect-expression that represents a template is followed by <(^X)< xv; / OK^^X<true>< xv; / OK} — end example]
[Example 2: struct A {struct S {}; };
struct B : A {using A::S; };
constexpr std::meta::info r1 =^^B::S; / error: A::S found through using-declaratorstruct C :virtual B {struct S {}; };
struct D :virtual B, C {};
D::S s; / OK, names C::S per [class.member.lookup]constexpr std::meta::info r2 =^^D::S; / OK, result C::S not found through using-declarator — end example]
Otherwise, if lookup finds a type alias A,
R represents the underlying entity of A
if A was introduced by the declaration of a template parameter;
otherwise, R represents A.
Otherwise, if the id-expression denotes an overload set S,
overload resolution for the expression &S with no target
shall select a unique function ([over.over]);
R represents that function.
[Example 3: template<typename T>void fn()requires(^T !=^^int);
template<typename T>void fn()requires(^T ==^^int);
template<typename T>void fn()requires(sizeof(T)==sizeof(int);
constexpr std::meta::info a =^^fn<char>; / OKconstexpr std::meta::info b =^^fn<int>; / error: ambiguousconstexpr std::meta::info c =^^std::vector; / OKtemplate<typename T>struct S {staticconstexpr std::meta::info r =^^T;
using type = T;
};
static_assert(S<int>::r ==^^int);
static_assert(^S<int>::type !=^^int);
typedefstruct X {} Y;
typedefstruct Z {} Z;
constexpr std::meta::info e =^^Y; / OK, represents the type alias Yconstexpr std::meta::info f =^^Z; / OK, represents the type alias Z, not the type ([basic.lookup.general]) — end example]