1824 lines
96 KiB
Markdown
1824 lines
96 KiB
Markdown
[expr.unary]
|
||
|
||
# 7 Expressions [[expr]](./#expr)
|
||
|
||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.unary)
|
||
|
||
### 7.6.2 Unary expressions [expr.unary]
|
||
|
||
#### [7.6.2.1](#general) General [[expr.unary.general]](expr.unary.general)
|
||
|
||
[1](#general-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5167)
|
||
|
||
Expressions with unary operators group right-to-left[.](#general-1.sentence-1)
|
||
|
||
[unary-expression:](#nt:unary-expression "7.6.2.1 General [expr.unary.general]")
|
||
[*postfix-expression*](expr.post.general#nt:postfix-expression "7.6.1.1 General [expr.post.general]")
|
||
[*unary-operator*](#nt:unary-operator "7.6.2.1 General [expr.unary.general]") [*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]")
|
||
++ [*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]")
|
||
-- [*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]")
|
||
[*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]")
|
||
sizeof [*unary-expression*](#nt:unary-expression "7.6.2.1 General [expr.unary.general]")
|
||
sizeof ( [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") )
|
||
sizeof ... ( [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") )
|
||
alignof ( [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") )
|
||
[*noexcept-expression*](#nt:noexcept-expression "7.6.2.7 noexcept operator [expr.unary.noexcept]")
|
||
[*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]")
|
||
[*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]")
|
||
[*reflect-expression*](#nt:reflect-expression "7.6.2.10 The reflection operator [expr.reflect]")
|
||
|
||
[unary-operator:](#nt:unary-operator "7.6.2.1 General [expr.unary.general]") one of
|
||
* & + - ! ~
|
||
|
||
#### [7.6.2.2](#op) Unary operators [[expr.unary.op]](expr.unary.op)
|
||
|
||
[1](#op-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5219)
|
||
|
||
The unary * operator performs [*indirection*](#def:indirection "7.6.2.2 Unary operators [expr.unary.op]")[.](#op-1.sentence-1)
|
||
|
||
Its operand shall be a prvalue of type âpointer to Tâ,
|
||
where T is an object or function type[.](#op-1.sentence-2)
|
||
|
||
The operator yields an lvalue of type T[.](#op-1.sentence-3)
|
||
|
||
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]](expr.typeid "7.6.1.8 Type identification")[.](#op-1.sentence-4)
|
||
|
||
[*Note [1](#op-note-1)*:
|
||
|
||
Indirection through a pointer to an out-of-lifetime object is valid ([[basic.life]](basic.life "6.8.4 Lifetime"))[.](#op-1.sentence-5)
|
||
|
||
â *end note*]
|
||
|
||
[*Note [2](#op-note-2)*:
|
||
|
||
Indirection through a pointer to an incomplete type (other thancv void) is valid[.](#op-1.sentence-6)
|
||
|
||
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]](conv.lval "7.3.2 Lvalue-to-rvalue conversion")[.](#op-1.sentence-7)
|
||
|
||
â *end note*]
|
||
|
||
[2](#op-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5241)
|
||
|
||
Each of the following unary operators yields a prvalue[.](#op-2.sentence-1)
|
||
|
||
[3](#op-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5244)
|
||
|
||
The operand of the unary & operator
|
||
shall be an lvalue of some type T[.](#op-3.sentence-1)
|
||
|
||
- [(3.1)](#op-3.1)
|
||
|
||
If the operand is a [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") or [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") 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[.](#op-3.1.sentence-1)
|
||
The result has type âpointer to member of class C of type Tâ
|
||
and designates C::m[.](#op-3.1.sentence-2)
|
||
[*Note [3](#op-note-3)*:
|
||
A [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") that names a member of a namespace-scope anonymous union
|
||
is considered to be a class member access expression ([[expr.prim.id.general]](expr.prim.id.general "7.5.5.1 General"))
|
||
and cannot be used to form a pointer to member[.](#op-3.1.sentence-3)
|
||
â *end note*]
|
||
|
||
- [(3.2)](#op-3.2)
|
||
|
||
Otherwise, the result has type âpointer to Tâ and points to
|
||
the designated object ([[intro.memory]](intro.memory "6.8.1 Memory model")) or function ([[basic.compound]](basic.compound "6.9.4 Compound types"))[.](#op-3.2.sentence-1)
|
||
If the operand designates an explicit object member function ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")),
|
||
the operand shall be
|
||
a [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") or a [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]")[.](#op-3.2.sentence-2)
|
||
[*Note [4](#op-note-4)*:
|
||
In particular, taking the address of a variable of type âcv Tâ
|
||
yields a pointer of type âpointer to cv Tâ[.](#op-3.2.sentence-3)
|
||
â *end note*]
|
||
|
||
[*Example [1](#op-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*]
|
||
|
||
[*Note [5](#op-note-5)*:
|
||
|
||
A pointer to member formed from a mutable non-static data
|
||
member ([[dcl.stc]](dcl.stc "9.2.2 Storage class specifiers")) does not reflect the mutable specifier
|
||
associated with the non-static data member[.](#op-3.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[4](#op-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5292)
|
||
|
||
A pointer to member is only formed when an explicit & is used
|
||
and its operand is
|
||
a [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") or [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") not enclosed in parentheses[.](#op-4.sentence-1)
|
||
|
||
[*Note [6](#op-note-6)*:
|
||
|
||
That is, the expression &(qualified-id), where the[*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") is enclosed in parentheses, does not form an
|
||
expression of type âpointer to memberâ[.](#op-4.sentence-2)
|
||
|
||
Neither doesqualified-id, because there is no implicit conversion from a[*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") 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]](conv.func "7.3.4 Function-to-pointer conversion"))[.](#op-4.sentence-3)
|
||
|
||
Nor is&unqualified-id a pointer to member, even within the scope of
|
||
the [*unqualified-id*](expr.prim.id.unqual#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]")'s class[.](#op-4.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[5](#op-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5309)
|
||
|
||
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[.](#op-5.sentence-1)
|
||
|
||
The operand of & shall not be a bit-field[.](#op-5.sentence-2)
|
||
|
||
[6](#op-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5315)
|
||
|
||
[*Note [7](#op-note-7)*:
|
||
|
||
The address of an overload set ([[over]](over "12 Overloading")) can be taken
|
||
only in a context that uniquely determines
|
||
which function is referred to (see [[over.over]](over.over "12.3 Address of an overload set"))[.](#op-6.sentence-1)
|
||
|
||
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â[.](#op-6.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[7](#op-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5327)
|
||
|
||
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[.](#op-7.sentence-1)
|
||
|
||
Integral promotion is performed on integral or enumeration
|
||
operands[.](#op-7.sentence-2)
|
||
|
||
The type of the result is the type of the promoted operand[.](#op-7.sentence-3)
|
||
|
||
[8](#op-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5335)
|
||
|
||
The operand of the unary - operator shall be a prvalue of
|
||
arithmetic or unscoped
|
||
enumeration type and the result is the negative of its operand[.](#op-8.sentence-1)
|
||
|
||
Integral
|
||
promotion is performed on integral or enumeration operands[.](#op-8.sentence-2)
|
||
|
||
The negative
|
||
of an unsigned quantity is computed by subtracting its value from 2n,
|
||
where n is the number of bits in the promoted operand[.](#op-8.sentence-3)
|
||
|
||
The type of the
|
||
result is the type of the promoted operand[.](#op-8.sentence-4)
|
||
|
||
[*Note [8](#op-note-8)*:
|
||
|
||
The result is the two's complement of the operand
|
||
(where operand and result are considered as unsigned)[.](#op-8.sentence-5)
|
||
|
||
â *end note*]
|
||
|
||
[9](#op-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5349)
|
||
|
||
The operand of the logical negation operator ! is contextually
|
||
converted to bool ([[conv]](conv "7.3 Standard conversions"));
|
||
its value is true if the converted operand is false and false otherwise[.](#op-9.sentence-1)
|
||
|
||
The type of the result is bool[.](#op-9.sentence-2)
|
||
|
||
[10](#op-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5357)
|
||
|
||
The operand of the ~ operator shall be a prvalue of
|
||
integral or unscoped enumeration type[.](#op-10.sentence-1)
|
||
|
||
Integral promotions are performed[.](#op-10.sentence-2)
|
||
|
||
The type of the result is the type of the promoted operand[.](#op-10.sentence-3)
|
||
|
||
Given the coefficients xi of the base-2 representation ([[basic.fundamental]](basic.fundamental "6.9.2 Fundamental types"))
|
||
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[.](#op-10.sentence-4)
|
||
|
||
[*Note [9](#op-note-9)*:
|
||
|
||
The result is the ones' complement of the operand
|
||
(where operand and result are considered as unsigned)[.](#op-10.sentence-5)
|
||
|
||
â *end note*]
|
||
|
||
There is an ambiguity
|
||
in the grammar when ~ is followed by
|
||
a [*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]") or [*computed-type-specifier*](dcl.type.simple#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]")[.](#op-10.sentence-6)
|
||
|
||
The ambiguity is resolved by treating ~ as the
|
||
operator rather than as the start of an [*unqualified-id*](expr.prim.id.unqual#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]") naming a destructor[.](#op-10.sentence-7)
|
||
|
||
[*Note [10](#op-note-10)*:
|
||
|
||
Because the grammar does not permit an operator to follow the., ->, or :: tokens, a ~ followed by
|
||
a [*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]") or [*computed-type-specifier*](dcl.type.simple#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") in a
|
||
member access expression or [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") is
|
||
unambiguously parsed as a destructor name[.](#op-10.sentence-8)
|
||
|
||
â *end note*]
|
||
|
||
#### [7.6.2.3](#expr.pre.incr) Increment and decrement [[expr.pre.incr]](expr.pre.incr)
|
||
|
||
[1](#expr.pre.incr-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5390)
|
||
|
||
The operand of prefix ++ or -- shall not be of type cv bool[.](#expr.pre.incr-1.sentence-1)
|
||
|
||
An operand with volatile-qualified type is deprecated;
|
||
see [[depr.volatile.type]](depr.volatile.type "D.4 Deprecated volatile types")[.](#expr.pre.incr-1.sentence-2)
|
||
|
||
The expression ++x is otherwise equivalent to x+=1 and
|
||
the expression --x is otherwise equivalent to x-=1 ([[expr.assign]](expr.assign "7.6.19 Assignment and compound assignment operators"))[.](#expr.pre.incr-1.sentence-3)
|
||
|
||
[*Note [1](#expr.pre.incr-note-1)*:
|
||
|
||
For postfix increment and decrement, see [[expr.post.incr]](expr.post.incr "7.6.1.6 Increment and decrement")[.](#expr.pre.incr-1.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
#### [7.6.2.4](#expr.await) Await [[expr.await]](expr.await)
|
||
|
||
[1](#expr.await-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5411)
|
||
|
||
The co_await expression is used to suspend evaluation of a
|
||
coroutine ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4 Coroutine definitions")) while awaiting completion of
|
||
the computation represented by the operand expression[.](#expr.await-1.sentence-1)
|
||
|
||
Suspending the evaluation of a coroutine
|
||
transfers control to its caller or resumer[.](#expr.await-1.sentence-2)
|
||
|
||
[await-expression:](#nt:await-expression "7.6.2.4 Await [expr.await]")
|
||
co_await [*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]")
|
||
|
||
[2](#expr.await-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5423)
|
||
|
||
An [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") shall appear only as a potentially-evaluated
|
||
expression within the [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") of a[*function-body*](dcl.fct.def.general#nt:function-body "9.6.1 General [dcl.fct.def.general]") or [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]"),
|
||
in either case
|
||
outside of a [*handler*](except.pre#nt:handler "14.1 Preamble [except.pre]") ([[except.pre]](except.pre "14.1 Preamble"))[.](#expr.await-2.sentence-1)
|
||
|
||
In a [*declaration-statement*](stmt.dcl#nt:declaration-statement "8.10 Declaration statement [stmt.dcl]") or in the[*simple-declaration*](dcl.pre#nt:simple-declaration "9.1 Preamble [dcl.pre]") (if any)
|
||
of an [*init-statement*](stmt.pre#nt:init-statement "8.1 Preamble [stmt.pre]"), an [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") shall appear only in an [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]") of that[*declaration-statement*](stmt.dcl#nt:declaration-statement "8.10 Declaration statement [stmt.dcl]") or [*simple-declaration*](dcl.pre#nt:simple-declaration "9.1 Preamble [dcl.pre]")[.](#expr.await-2.sentence-2)
|
||
|
||
An [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") shall not appear in a
|
||
default argument ([[dcl.fct.default]](dcl.fct.default "9.3.4.7 Default arguments"))[.](#expr.await-2.sentence-3)
|
||
|
||
An [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") shall not appear in the initializer of
|
||
a block variable with static or thread storage duration[.](#expr.await-2.sentence-4)
|
||
|
||
An [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") shall not be
|
||
a potentially-evaluated subexpression
|
||
of the predicate of a contract assertion ([[basic.contract]](basic.contract "6.11 Contract assertions"))[.](#expr.await-2.sentence-5)
|
||
|
||
A context within a function where an [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") can appear
|
||
is called a [*suspension context*](#def:suspension_context) of the function[.](#expr.await-2.sentence-6)
|
||
|
||
[3](#expr.await-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5444)
|
||
|
||
Evaluation of an [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") involves the following
|
||
auxiliary types, expressions, and objects:
|
||
|
||
- [(3.1)](#expr.await-3.1)
|
||
|
||
*p* is an lvalue naming the promise
|
||
object ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4 Coroutine definitions"))
|
||
of the enclosing coroutine and P is the type of that object[.](#expr.await-3.1.sentence-1)
|
||
|
||
- [(3.2)](#expr.await-3.2)
|
||
|
||
Unless
|
||
the [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") was implicitly produced by
|
||
a [*yield-expression*](expr.yield#nt:yield-expression "7.6.17 Yielding a value [expr.yield]") ([[expr.yield]](expr.yield "7.6.17 Yielding a value")),
|
||
an initial await expression,
|
||
or a final await expression ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4 Coroutine definitions")),
|
||
a search is performed for the name await_transform in the scope of P ([[class.member.lookup]](class.member.lookup "6.5.2 Member name lookup"))[.](#expr.await-3.2.sentence-1)
|
||
If this search is performed and finds at least one declaration,
|
||
then *a* is*p*.await_transform([*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]"));
|
||
otherwise, *a* is the [*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]")[.](#expr.await-3.2.sentence-2)
|
||
|
||
- [(3.3)](#expr.await-3.3)
|
||
|
||
*o* is determined by enumerating the applicableoperator co_await functions for an argument*a* ([[over.match.oper]](over.match.oper "12.2.2.3 Operators in expressions")), and choosing the best one through
|
||
overload resolution ([[over.match]](over.match "12.2 Overload resolution"))[.](#expr.await-3.3.sentence-1)
|
||
If overload resolution is ambiguous,
|
||
the program is ill-formed[.](#expr.await-3.3.sentence-2)
|
||
If no viable functions are found, *o* is *a*[.](#expr.await-3.3.sentence-3)
|
||
Otherwise, *o* is a call to the selected function
|
||
with the argument *a*[.](#expr.await-3.3.sentence-4)
|
||
If *o* would be a prvalue,
|
||
the temporary materialization conversion ([[conv.rval]](conv.rval "7.3.5 Temporary materialization conversion")) is applied[.](#expr.await-3.3.sentence-5)
|
||
|
||
- [(3.4)](#expr.await-3.4)
|
||
|
||
*e* is an lvalue
|
||
referring to the result of evaluating
|
||
the (possibly-converted) *o*[.](#expr.await-3.4.sentence-1)
|
||
|
||
- [(3.5)](#expr.await-3.5)
|
||
|
||
*h* is an object of typestd::coroutine_handle<P> referring to the enclosing coroutine[.](#expr.await-3.5.sentence-1)
|
||
|
||
- [(3.6)](#expr.await-3.6)
|
||
|
||
*await-ready* is the expression*e*.await_ready(),
|
||
contextually converted to bool[.](#expr.await-3.6.sentence-1)
|
||
|
||
- [(3.7)](#expr.await-3.7)
|
||
|
||
*await-suspend* is the expression*e*.await_suspend(*h*),
|
||
which shall be a prvalue of type void, bool, orstd::coroutine_handle<Z> for some type Z[.](#expr.await-3.7.sentence-1)
|
||
|
||
- [(3.8)](#expr.await-3.8)
|
||
|
||
*await-resume* is the expression*e*.await_resume()[.](#expr.await-3.8.sentence-1)
|
||
|
||
[4](#expr.await-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5507)
|
||
|
||
The [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") has the same type and value category
|
||
as the *await-resume* expression[.](#expr.await-4.sentence-1)
|
||
|
||
[5](#expr.await-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5511)
|
||
|
||
The [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") evaluates
|
||
the (possibly-converted) *o* expression and
|
||
the *await-ready* expression, then:
|
||
|
||
- [(5.1)](#expr.await-5.1)
|
||
|
||
If the result of *await-ready* is false,
|
||
the coroutine is considered suspended[.](#expr.await-5.1.sentence-1)
|
||
Then:
|
||
* [(5.1.1)](#expr.await-5.1.1)
|
||
|
||
If the type of *await-suspend* is std::coroutine_handle<Z>,*await-suspend*.resume() is evaluated[.](#expr.await-5.1.1.sentence-1)
|
||
[*Note [1](#expr.await-note-1)*:
|
||
This resumes the coroutine referred to
|
||
by the result of *await-suspend*[.](#expr.await-5.1.1.sentence-2)
|
||
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]](dcl.fct.def.coroutine "9.6.4 Coroutine definitions"))[.](#expr.await-5.1.1.sentence-3)
|
||
â *end note*]
|
||
|
||
* [(5.1.2)](#expr.await-5.1.2)
|
||
|
||
Otherwise, if the type of *await-suspend* is bool,*await-suspend* is evaluated,
|
||
and the coroutine is resumed if the result is false[.](#expr.await-5.1.2.sentence-1)
|
||
|
||
* [(5.1.3)](#expr.await-5.1.3)
|
||
|
||
Otherwise, *await-suspend* is evaluated[.](#expr.await-5.1.3.sentence-1)
|
||
|
||
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]](except.throw "14.2 Throwing an exception"))[.](#expr.await-5.1.sentence-3)
|
||
Otherwise, control flow returns
|
||
to the current coroutine caller or resumer ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4 Coroutine definitions"))
|
||
without exiting any scopes ([[stmt.jump]](stmt.jump "8.8 Jump statements"))[.](#expr.await-5.1.sentence-4)
|
||
The point in the coroutine
|
||
immediately prior to control returning to its caller or resumer
|
||
is a coroutine [*suspend point*](#def:suspend_point "7.6.2.4 Await [expr.await]")[.](#expr.await-5.1.sentence-5)
|
||
|
||
- [(5.2)](#expr.await-5.2)
|
||
|
||
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*](#nt:await-expression "7.6.2.4 Await [expr.await]")[.](#expr.await-5.2.sentence-1)
|
||
|
||
[*Note [2](#expr.await-note-2)*:
|
||
|
||
With respect to sequencing,
|
||
an [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") is indivisible ([[intro.execution]](intro.execution "6.10.1 Sequential execution"))[.](#expr.await-5.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[6](#expr.await-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5565)
|
||
|
||
[*Example [1](#expr.await-example-1)*: template <typename T>struct my_future {/* ... */bool await_ready(); void await_suspend(std::coroutine_handle<>);
|
||
T await_resume();};
|
||
|
||
template <class Rep, class Period>auto operator co_await(std::chrono::duration<Rep, Period> d) {struct awaiter { std::chrono::system_clock::duration duration; /* ... */ awaiter(std::chrono::system_clock::duration d) : duration(d) {}bool await_ready() const { return duration.count() <= 0; }void await_resume() {}void await_suspend(std::coroutine_handle<> h) { /* ... */ }}; return awaiter{d};}using namespace std::chrono;
|
||
|
||
my_future<int> h();
|
||
|
||
my_future<void> g() { std::cout << "just about to go to sleep...\n"; co_await 10ms;
|
||
std::cout << "resumed\n"; co_await h();}auto f(int x = co_await h()); // error: [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") outside of function suspension contextint a[] = { co_await h() }; // error: [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") outside of function suspension context â *end example*]
|
||
|
||
#### [7.6.2.5](#expr.sizeof) Sizeof [[expr.sizeof]](expr.sizeof)
|
||
|
||
[1](#expr.sizeof-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5607)
|
||
|
||
The sizeof operator yields the number of bytes
|
||
occupied by a non-potentially-overlapping object of the type
|
||
of its operand[.](#expr.sizeof-1.sentence-1)
|
||
|
||
The operand is either an expression,
|
||
which is an [unevaluated operand](expr.context#def:unevaluated_operand "7.2.3 Context dependence [expr.context]"), or a parenthesized[*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]")[.](#expr.sizeof-1.sentence-2)
|
||
|
||
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[.](#expr.sizeof-1.sentence-3)
|
||
|
||
The result of sizeof applied to any of the narrow character types is 1[.](#expr.sizeof-1.sentence-4)
|
||
|
||
The result ofsizeof applied to any other fundamental
|
||
type ([[basic.fundamental]](basic.fundamental "6.9.2 Fundamental types")) is implementation-defined[.](#expr.sizeof-1.sentence-5)
|
||
|
||
[*Note [1](#expr.sizeof-note-1)*:
|
||
|
||
In particular, the values of sizeof(bool), sizeof(char16_t),sizeof(char32_t), and sizeof(wchar_t) are
|
||
implementation-defined[.](#expr.sizeof-1.sentence-6)[57](#footnote-57 "sizeof(bool) is not required to be 1.")
|
||
|
||
â *end note*]
|
||
|
||
[*Note [2](#expr.sizeof-note-2)*:
|
||
|
||
See [[intro.memory]](intro.memory "6.8.1 Memory model") for the definition of byte
|
||
and [[basic.types.general]](basic.types.general#term.object.representation "6.9.1 General") for the definition of object representation[.](#expr.sizeof-1.sentence-7)
|
||
|
||
â *end note*]
|
||
|
||
[2](#expr.sizeof-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5641)
|
||
|
||
When applied to a reference type, the result is the size
|
||
of the referenced type[.](#expr.sizeof-2.sentence-1)
|
||
|
||
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[.](#expr.sizeof-2.sentence-2)
|
||
|
||
The result of applying sizeof to a
|
||
potentially-overlapping subobject is
|
||
the size of the type, not the size of the subobject[.](#expr.sizeof-2.sentence-3)[58](#footnote-58 "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.")
|
||
|
||
When applied to an array, the result is the total number of bytes in the
|
||
array[.](#expr.sizeof-2.sentence-4)
|
||
|
||
This implies that the size of an array of n elements isn times the size of an element[.](#expr.sizeof-2.sentence-5)
|
||
|
||
[3](#expr.sizeof-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5663)
|
||
|
||
The lvalue-to-rvalue ([[conv.lval]](conv.lval "7.3.2 Lvalue-to-rvalue conversion")),
|
||
array-to-pointer ([[conv.array]](conv.array "7.3.3 Array-to-pointer conversion")), and
|
||
function-to-pointer ([[conv.func]](conv.func "7.3.4 Function-to-pointer conversion")) standard conversions are not
|
||
applied to the operand of sizeof[.](#expr.sizeof-3.sentence-1)
|
||
|
||
If the operand is a prvalue,
|
||
the [temporary materialization conversion](conv.rval "7.3.5 Temporary materialization conversion [conv.rval]") is applied[.](#expr.sizeof-3.sentence-2)
|
||
|
||
[4](#expr.sizeof-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5672)
|
||
|
||
The [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") in a sizeof... expression shall name a
|
||
pack[.](#expr.sizeof-4.sentence-1)
|
||
|
||
The sizeof... operator yields the number of elements
|
||
in the pack ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates"))[.](#expr.sizeof-4.sentence-2)
|
||
|
||
A sizeof... expression is a pack expansion ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates"))[.](#expr.sizeof-4.sentence-3)
|
||
|
||
[*Example [1](#expr.sizeof-example-1)*: template<class... Types>struct count {static constexpr std::size_t value = sizeof...(Types);}; â *end example*]
|
||
|
||
[5](#expr.sizeof-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5686)
|
||
|
||
The result of sizeof and sizeof... is a prvalue of typestd::size_t[.](#expr.sizeof-5.sentence-1)
|
||
|
||
[*Note [3](#expr.sizeof-note-3)*:
|
||
|
||
A sizeof expression
|
||
is an integral constant expression ([[expr.const]](expr.const "7.7 Constant expressions"))[.](#expr.sizeof-5.sentence-2)
|
||
|
||
The [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") std::size_t is declared in the standard header[<cstddef>](cstddef.syn#header:%3ccstddef%3e "17.2.1 Header <cstddef> synopsis [cstddef.syn]") ([[cstddef.syn]](cstddef.syn "17.2.1 Header <cstddef> synopsis"), [[support.types.layout]](support.types.layout "17.2.4 Sizes, alignments, and offsets"))[.](#expr.sizeof-5.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[57)](#footnote-57)[57)](#footnoteref-57)
|
||
|
||
sizeof(bool) is not required to be 1[.](#footnote-57.sentence-1)
|
||
|
||
[58)](#footnote-58)[58)](#footnoteref-58)
|
||
|
||
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[.](#footnote-58.sentence-1)
|
||
|
||
#### [7.6.2.6](#expr.alignof) Alignof [[expr.alignof]](expr.alignof)
|
||
|
||
[1](#expr.alignof-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5700)
|
||
|
||
An alignof expression yields the alignment requirement
|
||
of its operand type[.](#expr.alignof-1.sentence-1)
|
||
|
||
The operand shall be a [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") representing a complete object type, or an array thereof, or a reference
|
||
to one of those types[.](#expr.alignof-1.sentence-2)
|
||
|
||
[2](#expr.alignof-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5708)
|
||
|
||
The result is a prvalue of type std::size_t[.](#expr.alignof-2.sentence-1)
|
||
|
||
[*Note [1](#expr.alignof-note-1)*:
|
||
|
||
An alignof expression
|
||
is an integral constant expression ([[expr.const]](expr.const "7.7 Constant expressions"))[.](#expr.alignof-2.sentence-2)
|
||
|
||
The [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") std::size_t is declared in the standard header[<cstddef>](cstddef.syn#header:%3ccstddef%3e "17.2.1 Header <cstddef> synopsis [cstddef.syn]") ([[cstddef.syn]](cstddef.syn "17.2.1 Header <cstddef> synopsis"), [[support.types.layout]](support.types.layout "17.2.4 Sizes, alignments, and offsets"))[.](#expr.alignof-2.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[3](#expr.alignof-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5717)
|
||
|
||
When alignof is applied to a reference type, the result
|
||
is the alignment of the referenced type[.](#expr.alignof-3.sentence-1)
|
||
|
||
When alignof is applied to an array type, the result is the alignment of the
|
||
element type[.](#expr.alignof-3.sentence-2)
|
||
|
||
#### [7.6.2.7](#noexcept) noexcept operator [[expr.unary.noexcept]](expr.unary.noexcept)
|
||
|
||
[noexcept-expression:](#nt:noexcept-expression "7.6.2.7 noexcept operator [expr.unary.noexcept]")
|
||
noexcept ( [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") )
|
||
|
||
[1](#noexcept-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5733)
|
||
|
||
The operand of the noexcept operator
|
||
is an unevaluated operand ([[expr.context]](expr.context#term.unevaluated.operand "7.2.3 Context dependence"))[.](#noexcept-1.sentence-1)
|
||
|
||
If the operand is a prvalue,
|
||
the temporary materialization conversion ([[conv.rval]](conv.rval "7.3.5 Temporary materialization conversion")) is applied[.](#noexcept-1.sentence-2)
|
||
|
||
[2](#noexcept-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5739)
|
||
|
||
The result of the noexcept operator is a prvalue of type bool[.](#noexcept-2.sentence-1)
|
||
|
||
The result is false if
|
||
the full-expression of the operand is potentially-throwing ([[except.spec]](except.spec "14.5 Exception specifications")), andtrue otherwise[.](#noexcept-2.sentence-2)
|
||
|
||
[*Note [1](#noexcept-note-1)*:
|
||
|
||
A [*noexcept-expression*](#nt:noexcept-expression "7.6.2.7 noexcept operator [expr.unary.noexcept]") is an integral constant expression ([[expr.const]](expr.const "7.7 Constant expressions"))[.](#noexcept-2.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
#### [7.6.2.8](#expr.new) New [[expr.new]](expr.new)
|
||
|
||
[1](#expr.new-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5752)
|
||
|
||
The [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") attempts to create an object of the[*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") or [*new-type-id*](#nt:new-type-id "7.6.2.8 New [expr.new]") ([[dcl.name]](dcl.name "9.3.2 Type names")) to which
|
||
it is applied[.](#expr.new-1.sentence-1)
|
||
|
||
The type of that object is the [*allocated type*](#def:type,allocated "7.6.2.8 New [expr.new]")[.](#expr.new-1.sentence-2)
|
||
|
||
This type shall be a complete object type ([[basic.types.general]](basic.types.general#term.incomplete.type "6.9.1 General")),
|
||
but not an abstract class type ([[class.abstract]](class.abstract "11.7.4 Abstract classes")) or array
|
||
thereof ([[intro.object]](intro.object "6.8.2 Object model"))[.](#expr.new-1.sentence-3)
|
||
|
||
[*Note [1](#expr.new-note-1)*:
|
||
|
||
Because references are not objects, references cannot be created by[*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]")*s*[.](#expr.new-1.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[*Note [2](#expr.new-note-2)*:
|
||
|
||
The [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") can be a cv-qualified type, in which case the
|
||
object created by the [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") has a cv-qualified type[.](#expr.new-1.sentence-5)
|
||
|
||
â *end note*]
|
||
|
||
[new-expression:](#nt:new-expression "7.6.2.8 New [expr.new]")
|
||
::opt new [*new-placement*](#nt:new-placement "7.6.2.8 New [expr.new]")opt [*new-type-id*](#nt:new-type-id "7.6.2.8 New [expr.new]") [*new-initializer*](#nt:new-initializer "7.6.2.8 New [expr.new]")opt
|
||
::opt new [*new-placement*](#nt:new-placement "7.6.2.8 New [expr.new]")opt ( [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") ) [*new-initializer*](#nt:new-initializer "7.6.2.8 New [expr.new]")opt
|
||
|
||
[new-placement:](#nt:new-placement "7.6.2.8 New [expr.new]")
|
||
( [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") )
|
||
|
||
[new-type-id:](#nt:new-type-id "7.6.2.8 New [expr.new]")
|
||
[*type-specifier-seq*](dcl.type.general#nt:type-specifier-seq "9.2.9.1 General [dcl.type.general]") [*new-declarator*](#nt:new-declarator "7.6.2.8 New [expr.new]")opt
|
||
|
||
[new-declarator:](#nt:new-declarator "7.6.2.8 New [expr.new]")
|
||
[*ptr-operator*](dcl.decl.general#nt:ptr-operator "9.3.1 General [dcl.decl.general]") [*new-declarator*](#nt:new-declarator "7.6.2.8 New [expr.new]")opt
|
||
[*noptr-new-declarator*](#nt:noptr-new-declarator "7.6.2.8 New [expr.new]")
|
||
|
||
[noptr-new-declarator:](#nt:noptr-new-declarator "7.6.2.8 New [expr.new]")
|
||
[ [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]")opt ] [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt
|
||
[*noptr-new-declarator*](#nt:noptr-new-declarator "7.6.2.8 New [expr.new]") [ [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]") ] [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt
|
||
|
||
[new-initializer:](#nt:new-initializer "7.6.2.8 New [expr.new]")
|
||
( [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]")opt )
|
||
[*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]")
|
||
|
||
[2](#expr.new-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5813)
|
||
|
||
If a [placeholder type](dcl.spec.auto "9.2.9.7 Placeholder type specifiers [dcl.spec.auto]") or
|
||
a placeholder for a deduced class type ([[dcl.type.class.deduct]](dcl.type.class.deduct "9.2.9.8 Deduced class template specialization types"))
|
||
appears in the[*type-specifier-seq*](dcl.type.general#nt:type-specifier-seq "9.2.9.1 General [dcl.type.general]") of a [*new-type-id*](#nt:new-type-id "7.6.2.8 New [expr.new]") or[*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") of a [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]"),
|
||
the allocated type is deduced as follows:
|
||
Let*init* be the [*new-initializer*](#nt:new-initializer "7.6.2.8 New [expr.new]"), if any,
|
||
andT be the [*new-type-id*](#nt:new-type-id "7.6.2.8 New [expr.new]") or [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") of
|
||
the [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]"), then the allocated type is the type
|
||
deduced for the variable x in the invented
|
||
declaration ([[dcl.spec.auto]](dcl.spec.auto "9.2.9.7 Placeholder type specifiers")):T x *init* ;
|
||
|
||
[*Example [1](#expr.new-example-1)*: new auto(1); // allocated type is intauto x = new auto('a'); // allocated type is char, x is of type char*template<class T> struct A { A(T, T); };auto y = new A{1, 2}; // allocated type is A<int> â *end example*]
|
||
|
||
[3](#expr.new-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5841)
|
||
|
||
The [*new-type-id*](#nt:new-type-id "7.6.2.8 New [expr.new]") in a [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") is the longest
|
||
possible sequence of [*new-declarator*](#nt:new-declarator "7.6.2.8 New [expr.new]")*s*[.](#expr.new-3.sentence-1)
|
||
|
||
[*Note [3](#expr.new-note-3)*:
|
||
|
||
This prevents ambiguities between the declarator operators &, &&,*, and [] and their expression counterparts[.](#expr.new-3.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[*Example [2](#expr.new-example-2)*: new int * i; // syntax error: parsed as (new int*) i, not as (new int)*i
|
||
|
||
The * is the pointer declarator and not the multiplication
|
||
operator[.](#expr.new-3.sentence-3)
|
||
|
||
â *end example*]
|
||
|
||
[4](#expr.new-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5856)
|
||
|
||
[*Note [4](#expr.new-note-4)*:
|
||
|
||
Parentheses in a [*new-type-id*](#nt:new-type-id "7.6.2.8 New [expr.new]") of a [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") can have surprising effects[.](#expr.new-4.sentence-1)
|
||
|
||
[*Example [3](#expr.new-example-3)*:
|
||
|
||
new int(*[10])(); // error is ill-formed because the binding is(new int) (*[10])(); // error
|
||
|
||
Instead, the explicitly parenthesized version of the new operator can be used to create objects of compound
|
||
types ([[basic.compound]](basic.compound "6.9.4 Compound types")):
|
||
|
||
new (int (*[10])()); allocates an array of 10 pointers to functions (taking no
|
||
argument and returning int)[.](#expr.new-4.sentence-4)
|
||
|
||
â *end example*]
|
||
|
||
â *end note*]
|
||
|
||
[5](#expr.new-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5882)
|
||
|
||
The [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") in a [*noptr-new-declarator*](#nt:noptr-new-declarator "7.6.2.8 New [expr.new]") appertains
|
||
to the associated array type[.](#expr.new-5.sentence-1)
|
||
|
||
[6](#expr.new-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5886)
|
||
|
||
Every [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]") in a[*noptr-new-declarator*](#nt:noptr-new-declarator "7.6.2.8 New [expr.new]") shall be a converted constant
|
||
expression ([[expr.const]](expr.const "7.7 Constant expressions")) of type std::size_t and
|
||
its value shall be greater than zero[.](#expr.new-6.sentence-1)
|
||
|
||
[*Example [4](#expr.new-example-4)*:
|
||
|
||
Given the definition int n = 42,new float[n][5] is well-formed (because n is the[*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") of a [*noptr-new-declarator*](#nt:noptr-new-declarator "7.6.2.8 New [expr.new]")), butnew float[5][n] is ill-formed (because n is not a
|
||
constant expression)[.](#expr.new-6.sentence-2)
|
||
|
||
Furthermore,new float[0] is well-formed
|
||
(because 0 is the [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") of a [*noptr-new-declarator*](#nt:noptr-new-declarator "7.6.2.8 New [expr.new]"),
|
||
where a value of zero results in the allocation of an array with no elements),
|
||
but new float[n][0] is ill-formed
|
||
(because 0 is the [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]") of a [*noptr-new-declarator*](#nt:noptr-new-declarator "7.6.2.8 New [expr.new]"),
|
||
where only values greater than zero are allowed)[.](#expr.new-6.sentence-3)
|
||
|
||
â *end example*]
|
||
|
||
[7](#expr.new-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5908)
|
||
|
||
If the [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") or [*new-type-id*](#nt:new-type-id "7.6.2.8 New [expr.new]") denotes an array type of unknown bound ([[dcl.array]](dcl.array "9.3.4.5 Arrays")),
|
||
the [*new-initializer*](#nt:new-initializer "7.6.2.8 New [expr.new]") shall not be omitted;
|
||
the allocated object is an array with n elements,
|
||
where n is determined from the number of initial elements
|
||
supplied in
|
||
the [*new-initializer*](#nt:new-initializer "7.6.2.8 New [expr.new]") ([[dcl.init.aggr]](dcl.init.aggr "9.5.2 Aggregates"), [[dcl.init.string]](dcl.init.string "9.5.3 Character arrays"))[.](#expr.new-7.sentence-1)
|
||
|
||
[8](#expr.new-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5917)
|
||
|
||
If the [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") in a [*noptr-new-declarator*](#nt:noptr-new-declarator "7.6.2.8 New [expr.new]") is present, it is implicitly converted to std::size_t[.](#expr.new-8.sentence-1)
|
||
|
||
The value of the [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") is invalid if
|
||
|
||
- [(8.1)](#expr.new-8.1)
|
||
|
||
the expression is of non-class type and its value before converting tostd::size_t is less than zero;
|
||
|
||
- [(8.2)](#expr.new-8.2)
|
||
|
||
the expression is of class type and its value before application of the second
|
||
standard conversion ([[over.ics.user]](over.ics.user "12.2.4.2.3 User-defined conversion sequences"))[59](#footnote-59 "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.") is less than zero;
|
||
|
||
- [(8.3)](#expr.new-8.3)
|
||
|
||
its value is such that the size of the allocated object would exceed theimplementation-defined [limit](implimits "Annex B (informative) Implementation quantities [implimits]"); or
|
||
|
||
- [(8.4)](#expr.new-8.4)
|
||
|
||
the [*new-initializer*](#nt:new-initializer "7.6.2.8 New [expr.new]") is a [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]") and the
|
||
number of array elements for which initializers are provided (including the
|
||
terminating '\0' in a [*string-literal*](lex.string#nt:string-literal "5.13.5 String literals [lex.string]") ([[lex.string]](lex.string "5.13.5 String literals"))) exceeds the
|
||
number of elements to initialize[.](#expr.new-8.sentence-2)
|
||
|
||
If the value of the [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") is invalid after converting to std::size_t:
|
||
|
||
- [(8.5)](#expr.new-8.5)
|
||
|
||
if the [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") is a potentially-evaluated core constant expression,
|
||
the program is ill-formed;
|
||
|
||
- [(8.6)](#expr.new-8.6)
|
||
|
||
otherwise, an allocation function is not called; instead
|
||
* [(8.6.1)](#expr.new-8.6.1)
|
||
|
||
if the allocation function that would have been called
|
||
has a non-throwing exception specification ([[except.spec]](except.spec "14.5 Exception specifications")),
|
||
the value of the [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") is the null pointer value of the required result type;
|
||
|
||
* [(8.6.2)](#expr.new-8.6.2)
|
||
|
||
otherwise, the [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") terminates by throwing an
|
||
exception of a type that would match a handler ([[except.handle]](except.handle "14.4 Handling an exception")) of type[std::bad_array_new_length](new.badlength "17.6.4.2 Class bad_array_new_length [new.badlength]")[.](#expr.new-8.sentence-3)
|
||
|
||
When the value of the [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") is zero, the allocation
|
||
function is called to allocate an array with no elements[.](#expr.new-8.sentence-4)
|
||
|
||
[9](#expr.new-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5972)
|
||
|
||
If the allocated type is an array,
|
||
the [*new-initializer*](#nt:new-initializer "7.6.2.8 New [expr.new]") is a [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]"), and
|
||
the [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") is potentially-evaluated and not a core constant expression,
|
||
the semantic constraints of copy-initializing a hypothetical element of
|
||
the array from an empty initializer list
|
||
are checked ([[dcl.init.list]](dcl.init.list "9.5.5 List-initialization"))[.](#expr.new-9.sentence-1)
|
||
|
||
[*Note [5](#expr.new-note-5)*:
|
||
|
||
The array can contain more elements than there are
|
||
elements in the [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]"),
|
||
requiring initialization of the remainder of the array elements from
|
||
an empty initializer list[.](#expr.new-9.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[10](#expr.new-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5987)
|
||
|
||
Objects created by a [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") have dynamic storage
|
||
duration ([[basic.stc.dynamic]](basic.stc.dynamic "6.8.6.5 Dynamic storage duration"))[.](#expr.new-10.sentence-1)
|
||
|
||
[*Note [6](#expr.new-note-6)*:
|
||
|
||
The lifetime of such an object is not necessarily restricted to the
|
||
scope in which it is created[.](#expr.new-10.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[11](#expr.new-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5997)
|
||
|
||
When the allocated type is âarray of N Tâ
|
||
(that is, the [*noptr-new-declarator*](#nt:noptr-new-declarator "7.6.2.8 New [expr.new]") syntax is used or the[*new-type-id*](#nt:new-type-id "7.6.2.8 New [expr.new]") or [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") denotes an array type),
|
||
the [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") yields a prvalue of type âpointer to Tâ
|
||
that points to the initial element (if any) of the array[.](#expr.new-11.sentence-1)
|
||
|
||
Otherwise, let T be the allocated type;
|
||
the [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") is a prvalue of type âpointer to Tâ
|
||
that points to the object created[.](#expr.new-11.sentence-2)
|
||
|
||
[*Note [7](#expr.new-note-7)*:
|
||
|
||
Both new int and new int[10] have type int* and
|
||
the type of new int[i][10] is int (*)[10][.](#expr.new-11.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[12](#expr.new-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6013)
|
||
|
||
A [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") may obtain storage for the object by calling an
|
||
allocation function ([[basic.stc.dynamic.allocation]](basic.stc.dynamic.allocation "6.8.6.5.2 Allocation functions"))[.](#expr.new-12.sentence-1)
|
||
|
||
If
|
||
the [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") terminates by throwing an exception, it
|
||
may release storage by calling a [deallocation
|
||
function](basic.stc.dynamic.deallocation "6.8.6.5.3 Deallocation functions [basic.stc.dynamic.deallocation]")[.](#expr.new-12.sentence-2)
|
||
|
||
If the allocated type
|
||
is a non-array type, the allocation function's name isoperator new and the deallocation function's name isoperator delete[.](#expr.new-12.sentence-3)
|
||
|
||
If the allocated type is an array type, the
|
||
allocation function's name isoperator new[] and the deallocation function's name isoperator delete[][.](#expr.new-12.sentence-4)
|
||
|
||
[*Note [8](#expr.new-note-8)*:
|
||
|
||
An implementation is expected to provide default definitions for the global
|
||
allocation
|
||
functions ([[basic.stc.dynamic]](basic.stc.dynamic "6.8.6.5 Dynamic storage duration"), [[new.delete.single]](new.delete.single "17.6.3.2 Single-object forms"), [[new.delete.array]](new.delete.array "17.6.3.3 Array forms"))[.](#expr.new-12.sentence-5)
|
||
|
||
A C++ program can provide alternative definitions of
|
||
these functions ([[replacement.functions]](replacement.functions "16.4.5.6 Replacement functions")) and/or class-specific
|
||
versions ([[class.free]](class.free "11.4.11 Allocation and deallocation functions"))[.](#expr.new-12.sentence-6)
|
||
|
||
The set of allocation and deallocation functions that can be called
|
||
by a [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") can include functions that do not perform allocation or deallocation;
|
||
for example, see [[new.delete.placement]](new.delete.placement "17.6.3.4 Non-allocating forms")[.](#expr.new-12.sentence-7)
|
||
|
||
â *end note*]
|
||
|
||
[13](#expr.new-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6043)
|
||
|
||
If the [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") 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]](class.member.lookup "6.5.2 Member name lookup"))[.](#expr.new-13.sentence-1)
|
||
|
||
Otherwise, or if nothing is found,
|
||
the allocation function's name is looked up by
|
||
searching for it in the global scope[.](#expr.new-13.sentence-2)
|
||
|
||
[14](#expr.new-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6054)
|
||
|
||
An implementation is allowed to omit a call to a replaceable global allocation
|
||
function ([[new.delete.single]](new.delete.single "17.6.3.2 Single-object forms"), [[new.delete.array]](new.delete.array "17.6.3.3 Array forms"))[.](#expr.new-14.sentence-1)
|
||
|
||
When it does so,
|
||
the storage is instead provided by the implementation or provided by extending
|
||
the allocation of another [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]")[.](#expr.new-14.sentence-2)
|
||
|
||
[15](#expr.new-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6060)
|
||
|
||
During an evaluation of a constant expression,
|
||
a call to a replaceable allocation function is always omitted ([[expr.const]](expr.const "7.7 Constant expressions"))[.](#expr.new-15.sentence-1)
|
||
|
||
[16](#expr.new-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6064)
|
||
|
||
The implementation may
|
||
extend the allocation of a [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") e1 to provide
|
||
storage for a [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") e2 if the
|
||
following would be true were the allocation not extended:
|
||
|
||
- [(16.1)](#expr.new-16.1)
|
||
|
||
the evaluation of e1 is sequenced before the evaluation ofe2, and
|
||
|
||
- [(16.2)](#expr.new-16.2)
|
||
|
||
e2 is evaluated whenever e1 obtains storage, and
|
||
|
||
- [(16.3)](#expr.new-16.3)
|
||
|
||
both e1 and e2 invoke the same replaceable global
|
||
allocation function, and
|
||
|
||
- [(16.4)](#expr.new-16.4)
|
||
|
||
if the allocation function invoked by e1 and e2 is
|
||
throwing, any exceptions thrown in the evaluation of either e1 ore2 would be first caught in the same handler, and
|
||
|
||
- [(16.5)](#expr.new-16.5)
|
||
|
||
the pointer values produced by e1 and e2 are operands to
|
||
evaluated [*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]")*s*, and
|
||
|
||
- [(16.6)](#expr.new-16.6)
|
||
|
||
the evaluation of e2 is sequenced before the evaluation of the[*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]") whose operand is the pointer value produced
|
||
by e1[.](#expr.new-16.sentence-1)
|
||
|
||
[*Example [5](#expr.new-example-5)*: void can_merge(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]};
|
||
|
||
g(a.get(), b.get(), c.get());}void cannot_merge(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*]
|
||
|
||
[17](#expr.new-17)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6114)
|
||
|
||
When a [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") calls an allocation function and that
|
||
allocation has not been extended, the[*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") passes the amount of space requested to the
|
||
allocation function as the first argument of typestd::size_t[.](#expr.new-17.sentence-1)
|
||
|
||
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]](new.delete.placement "17.6.3.4 Non-allocating forms"))[.](#expr.new-17.sentence-2)
|
||
|
||
For arrays ofchar, unsigned char, and std::byte,
|
||
the difference between the
|
||
result of the [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") and the address returned by the
|
||
allocation function shall be an integral multiple of the
|
||
strictest fundamental[alignment requirement](basic.align "6.8.3 Alignment [basic.align]") of any object type whose size
|
||
is no greater than the size of the array being created[.](#expr.new-17.sentence-3)
|
||
|
||
[*Note [9](#expr.new-note-9)*:
|
||
|
||
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[.](#expr.new-17.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[18](#expr.new-18)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6140)
|
||
|
||
When a [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") 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[.](#expr.new-18.sentence-1)
|
||
|
||
[19](#expr.new-19)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6147)
|
||
|
||
The [*new-placement*](#nt:new-placement "7.6.2.8 New [expr.new]") syntax is used to supply additional
|
||
arguments to an allocation function; such an expression is called
|
||
a [*placement* ](#def:new-expression,placement "7.6.2.8 New [expr.new]")*[*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]")*[.](#expr.new-19.sentence-1)
|
||
|
||
[20](#expr.new-20)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6153)
|
||
|
||
Overload resolution is
|
||
performed on a function call created by assembling an argument list[.](#expr.new-20.sentence-1)
|
||
|
||
The first argument is
|
||
the amount of space requested,
|
||
and has type std::size_t[.](#expr.new-20.sentence-2)
|
||
|
||
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[.](#expr.new-20.sentence-3)
|
||
|
||
If the [*new-placement*](#nt:new-placement "7.6.2.8 New [expr.new]") syntax is used,
|
||
the [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1 General [dcl.init.general]")*s* in its [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") are the succeeding arguments[.](#expr.new-20.sentence-4)
|
||
|
||
If no matching function is found then
|
||
|
||
- [(20.1)](#expr.new-20.1)
|
||
|
||
if the allocated object type has new-extended alignment,
|
||
the alignment argument is removed from the argument list;
|
||
|
||
- [(20.2)](#expr.new-20.2)
|
||
|
||
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;
|
||
|
||
and then overload resolution is performed again[.](#expr.new-20.sentence-5)
|
||
|
||
[21](#expr.new-21)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6181)
|
||
|
||
[*Example [6](#expr.new-example-6)*:
|
||
|
||
- [(21.1)](#expr.new-21.1)
|
||
|
||
new T results in one of the following calls:operator new(sizeof(T))operator new(sizeof(T), std::align_val_t(alignof(T)))
|
||
|
||
- [(21.2)](#expr.new-21.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)
|
||
|
||
- [(21.3)](#expr.new-21.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)))
|
||
|
||
- [(21.4)](#expr.new-21.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*](#nt:new-expression "7.6.2.8 New [expr.new]") will be offset by this amount from the value
|
||
returned by operator new[].
|
||
|
||
This overhead may be applied in all
|
||
array [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]")*s*, including those referencing
|
||
a placement allocation function, except when referencing
|
||
the library function operator new[](std::size_t, void*)[.](#expr.new-21.sentence-1)
|
||
|
||
The amount of overhead may vary from one
|
||
invocation of new to another[.](#expr.new-21.sentence-2)
|
||
|
||
â *end example*]
|
||
|
||
[22](#expr.new-22)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6216)
|
||
|
||
[*Note [10](#expr.new-note-10)*:
|
||
|
||
Unless an allocation function has a non-throwing[exception specification](except.spec "14.5 Exception specifications [except.spec]"),
|
||
it indicates failure to allocate storage by throwing astd::bad_alloc exception ([[basic.stc.dynamic.allocation]](basic.stc.dynamic.allocation "6.8.6.5.2 Allocation functions"), [[except]](except "14 Exception handling"), [[bad.alloc]](bad.alloc "17.6.4.1 Class bad_alloc"));
|
||
it returns a non-null pointer otherwise[.](#expr.new-22.sentence-1)
|
||
|
||
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[.](#expr.new-22.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
If the allocation function is a non-allocating
|
||
form ([[new.delete.placement]](new.delete.placement "17.6.3.4 Non-allocating forms")) that returns null,
|
||
the behavior is undefined[.](#expr.new-22.sentence-3)
|
||
|
||
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*](#nt:new-expression "7.6.2.8 New [expr.new]") shall be null[.](#expr.new-22.sentence-4)
|
||
|
||
[23](#expr.new-23)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6238)
|
||
|
||
[*Note [11](#expr.new-note-11)*:
|
||
|
||
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[.](#expr.new-23.sentence-1)
|
||
|
||
The block of storage is assumed to be
|
||
appropriately aligned ([[basic.align]](basic.align "6.8.3 Alignment"))
|
||
and of the requested size[.](#expr.new-23.sentence-2)
|
||
|
||
The address of the created object will not
|
||
necessarily be the same as that of the block if the object is an array[.](#expr.new-23.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[24](#expr.new-24)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6248)
|
||
|
||
A [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") that creates an object of type T initializes that object as follows:
|
||
|
||
- [(24.1)](#expr.new-24.1)
|
||
|
||
If the [*new-initializer*](#nt:new-initializer "7.6.2.8 New [expr.new]") is omitted, the object is
|
||
default-initialized ([[dcl.init]](dcl.init "9.5 Initializers"))[.](#expr.new-24.1.sentence-1)
|
||
[*Note [12](#expr.new-note-12)*:
|
||
If no initialization
|
||
is performed, the object has an indeterminate value[.](#expr.new-24.1.sentence-2)
|
||
â *end note*]
|
||
|
||
- [(24.2)](#expr.new-24.2)
|
||
|
||
Otherwise, the [*new-initializer*](#nt:new-initializer "7.6.2.8 New [expr.new]") is interpreted according to
|
||
the initialization rules of [[dcl.init]](dcl.init "9.5 Initializers") for direct-initialization[.](#expr.new-24.2.sentence-1)
|
||
|
||
[25](#expr.new-25)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6267)
|
||
|
||
The invocation of the allocation function is sequenced before
|
||
the evaluations of expressions in the [*new-initializer*](#nt:new-initializer "7.6.2.8 New [expr.new]")[.](#expr.new-25.sentence-1)
|
||
|
||
Initialization of
|
||
the allocated object is sequenced before thevalue computation of the[*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]")[.](#expr.new-25.sentence-2)
|
||
|
||
[26](#expr.new-26)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6277)
|
||
|
||
If the [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") creates an array of objects of class type, the destructor is potentially
|
||
invoked ([[class.dtor]](class.dtor "11.4.7 Destructors"))[.](#expr.new-26.sentence-1)
|
||
|
||
[27](#expr.new-27)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6282)
|
||
|
||
If any part of the object initialization described above[60](#footnote-60 "This can include evaluating a new-initializer and/or calling a constructor.") 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*](#nt:new-expression "7.6.2.8 New [expr.new]")[.](#expr.new-27.sentence-1)
|
||
|
||
If no unambiguous matching deallocation function can be found,
|
||
propagating the exception does not cause the object's memory to be
|
||
freed[.](#expr.new-27.sentence-2)
|
||
|
||
[*Note [13](#expr.new-note-13)*:
|
||
|
||
This is appropriate when the called allocation function does not
|
||
allocate memory; otherwise, it is likely to result in a memory leak[.](#expr.new-27.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[28](#expr.new-28)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6302)
|
||
|
||
If the [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") 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[.](#expr.new-28.sentence-1)
|
||
|
||
Otherwise, or if nothing is found,
|
||
the deallocation function's name is looked up by
|
||
searching for it in the global scope[.](#expr.new-28.sentence-2)
|
||
|
||
[29](#expr.new-29)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6312)
|
||
|
||
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]](dcl.fct "9.3.4.6 Functions")), all
|
||
parameter types except the first are identical[.](#expr.new-29.sentence-1)
|
||
|
||
If
|
||
the lookup finds a single matching deallocation function, that function
|
||
will be called; otherwise, no deallocation function will be called[.](#expr.new-29.sentence-2)
|
||
|
||
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[.](#expr.new-29.sentence-3)
|
||
|
||
For a non-placement allocation function, the normal deallocation
|
||
function lookup is used to find the matching deallocation
|
||
function ([[expr.delete]](#expr.delete "7.6.2.9 Delete"))[.](#expr.new-29.sentence-4)
|
||
|
||
In any case,
|
||
the matching deallocation function (if any) shall be non-deleted and
|
||
accessible from the point where the [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") appears[.](#expr.new-29.sentence-5)
|
||
|
||
[*Example [7](#expr.new-example-7)*: 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; // error: non-placement deallocation function matches// placement allocation function â *end example*]
|
||
|
||
[30](#expr.new-30)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6345)
|
||
|
||
If a [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") calls a deallocation function, it passes
|
||
the value returned from the allocation function call as the first
|
||
argument of type void*[.](#expr.new-30.sentence-1)
|
||
|
||
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*](#nt:new-placement "7.6.2.8 New [expr.new]") syntax[.](#expr.new-30.sentence-2)
|
||
|
||
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[.](#expr.new-30.sentence-3)
|
||
|
||
[59)](#footnote-59)[59)](#footnoteref-59)
|
||
|
||
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[.](#footnote-59.sentence-1)
|
||
|
||
[60)](#footnote-60)[60)](#footnoteref-60)
|
||
|
||
This can
|
||
include evaluating a [*new-initializer*](#nt:new-initializer "7.6.2.8 New [expr.new]") and/or calling
|
||
a constructor[.](#footnote-60.sentence-1)
|
||
|
||
#### [7.6.2.9](#expr.delete) Delete [[expr.delete]](expr.delete)
|
||
|
||
[1](#expr.delete-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6360)
|
||
|
||
The [*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]") operator destroys a[most derived object](intro.object#def:most_derived_object "6.8.2 Object model [intro.object]") or array created by a[*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]")[.](#expr.delete-1.sentence-1)
|
||
|
||
[delete-expression:](#nt:delete-expression "7.6.2.9 Delete [expr.delete]")
|
||
::opt delete [*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]")
|
||
::opt delete [ ] [*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]")
|
||
|
||
The first alternative is a[*single-object delete expression*](#def:delete,single-object "7.6.2.9 Delete [expr.delete]"), and the
|
||
second is an [*array delete expression*](#def:delete,array "7.6.2.9 Delete [expr.delete]")[.](#expr.delete-1.sentence-2)
|
||
|
||
Whenever the delete keyword is immediately followed by empty square
|
||
brackets, it shall be interpreted as the second alternative[.](#expr.delete-1.sentence-3)[61](#footnote-61 "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.")
|
||
|
||
If the operand is of
|
||
class type, it is contextually implicitly converted ([[conv]](conv "7.3 Standard conversions"))
|
||
to a pointer to object
|
||
type
|
||
and the converted operand is used in place of the original operand
|
||
for the remainder of this subclause[.](#expr.delete-1.sentence-4)
|
||
|
||
Otherwise, it shall be a prvalue of pointer to object type[.](#expr.delete-1.sentence-5)
|
||
|
||
The [*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]") has typevoid[.](#expr.delete-1.sentence-6)
|
||
|
||
[2](#expr.delete-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6394)
|
||
|
||
In a single-object delete expression, the value of the operand ofdelete may be a null pointer value,
|
||
a pointer value
|
||
that resulted from a previous non-array [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]"), or
|
||
a pointer to a base class subobject
|
||
of an object created by such a [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]")[.](#expr.delete-2.sentence-1)
|
||
|
||
If not, the behavior is undefined[.](#expr.delete-2.sentence-2)
|
||
|
||
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*](#nt:new-expression "7.6.2.8 New [expr.new]") whose
|
||
allocation function was not a non-allocating form ([[new.delete.placement]](new.delete.placement "17.6.3.4 Non-allocating forms"))[.](#expr.delete-2.sentence-3)[62](#footnote-62 "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.")
|
||
|
||
If not, the behavior is undefined[.](#expr.delete-2.sentence-4)
|
||
|
||
[*Note [1](#expr.delete-note-1)*:
|
||
|
||
This means that the syntax of the [*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]") must
|
||
match the type of the object allocated by new, not the syntax of the[*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]")[.](#expr.delete-2.sentence-5)
|
||
|
||
â *end note*]
|
||
|
||
[*Note [2](#expr.delete-note-2)*:
|
||
|
||
A pointer to a const type can be the operand of a[*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]"); it is not necessary to cast away the
|
||
constness ([[expr.const.cast]](expr.const.cast "7.6.1.11 Const cast")) of the pointer expression before it is
|
||
used as the operand of the [*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]")[.](#expr.delete-2.sentence-6)
|
||
|
||
â *end note*]
|
||
|
||
[3](#expr.delete-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6427)
|
||
|
||
In a single-object delete expression, if the static type of the object to be
|
||
deleted is not similar ([[conv.qual]](conv.qual "7.3.6 Qualification conversions")) 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[.](#expr.delete-3.sentence-1)
|
||
|
||
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[.](#expr.delete-3.sentence-2)
|
||
|
||
[4](#expr.delete-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6439)
|
||
|
||
If the object being deleted has incomplete class type at the point of deletion,
|
||
the program is ill-formed[.](#expr.delete-4.sentence-1)
|
||
|
||
[5](#expr.delete-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6444)
|
||
|
||
If the value of the operand of the [*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]") is not a
|
||
null pointer value
|
||
and the selected deallocation function (see below)
|
||
is not a destroying operator delete,
|
||
evaluating the [*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]") invokes the
|
||
destructor (if any) for the object or the elements of the array being
|
||
deleted[.](#expr.delete-5.sentence-1)
|
||
|
||
The destructor shall be accessible from the point where
|
||
the [*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]") appears[.](#expr.delete-5.sentence-2)
|
||
|
||
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]](class.base.init "11.9.3 Initializing bases and members"))[.](#expr.delete-5.sentence-3)
|
||
|
||
[6](#expr.delete-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6459)
|
||
|
||
If the value of the operand of the [*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]") is not a
|
||
null pointer value, then:
|
||
|
||
- [(6.1)](#expr.delete-6.1)
|
||
|
||
If the allocation call for the [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") for the object to
|
||
be deleted was not omitted and the allocation was not extended ([[expr.new]](#expr.new "7.6.2.8 New")), the[*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]") shall call a [deallocation
|
||
function](basic.stc.dynamic.deallocation "6.8.6.5.3 Deallocation functions [basic.stc.dynamic.deallocation]")[.](#expr.delete-6.1.sentence-1)
|
||
The value returned from the
|
||
allocation call of the [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") shall be passed as the
|
||
first argument to the deallocation function[.](#expr.delete-6.1.sentence-2)
|
||
|
||
- [(6.2)](#expr.delete-6.2)
|
||
|
||
Otherwise, if the allocation was extended or was provided by extending the
|
||
allocation of another [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]"), and the[*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]") for every other pointer value produced by a[*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") that had storage provided by the extended[*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") has been evaluated, the[*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]") shall call a deallocation function[.](#expr.delete-6.2.sentence-1)
|
||
The value
|
||
returned from the allocation call of the extended [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]") shall be passed as the first argument to the deallocation function[.](#expr.delete-6.2.sentence-2)
|
||
|
||
- [(6.3)](#expr.delete-6.3)
|
||
|
||
Otherwise, the [*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]") will not call a
|
||
deallocation function[.](#expr.delete-6.3.sentence-1)
|
||
|
||
[*Note [3](#expr.delete-note-3)*:
|
||
|
||
The deallocation function is called regardless of whether the destructor
|
||
for the object or some element of the array throws an exception[.](#expr.delete-6.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
If the value of the operand of the [*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]") is a
|
||
null pointer value, it is unspecified whether a deallocation function will be
|
||
called as described above[.](#expr.delete-6.sentence-3)
|
||
|
||
[7](#expr.delete-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6493)
|
||
|
||
If a deallocation function is called,
|
||
it is operator delete for a single-object delete expression oroperator delete[] for an array delete expression[.](#expr.delete-7.sentence-1)
|
||
|
||
[*Note [4](#expr.delete-note-4)*:
|
||
|
||
An implementation provides default definitions of the global
|
||
deallocation functions ([[new.delete.single]](new.delete.single "17.6.3.2 Single-object forms"), [[new.delete.array]](new.delete.array "17.6.3.3 Array forms"))[.](#expr.delete-7.sentence-2)
|
||
|
||
A C++ program can provide alternative definitions of these
|
||
functions ([[replacement.functions]](replacement.functions "16.4.5.6 Replacement functions")), and/or class-specific
|
||
versions ([[class.free]](class.free "11.4.11 Allocation and deallocation functions"))[.](#expr.delete-7.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[8](#expr.delete-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6506)
|
||
|
||
If the keyword delete in a [*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]") 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:
|
||
|
||
- [(8.1)](#expr.delete-8.1)
|
||
|
||
For a single-object delete expression,
|
||
if the operand is a pointer to cv T andT 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]](class.dtor "11.4.7 Destructors"))[.](#expr.delete-8.1.sentence-1)
|
||
|
||
- [(8.2)](#expr.delete-8.2)
|
||
|
||
Otherwise,
|
||
a search is performed for the deallocation function's name
|
||
in the scope of T[.](#expr.delete-8.2.sentence-1)
|
||
|
||
Otherwise, or if nothing is found,
|
||
the deallocation function's name is looked up by
|
||
searching for it in the global scope[.](#expr.delete-8.sentence-2)
|
||
|
||
In any case, any declarations
|
||
other than of usual deallocation functions ([[basic.stc.dynamic.deallocation]](basic.stc.dynamic.deallocation "6.8.6.5.3 Deallocation functions"))
|
||
are discarded[.](#expr.delete-8.sentence-3)
|
||
|
||
[*Note [5](#expr.delete-note-5)*:
|
||
|
||
If only a placement deallocation function is found in a class,
|
||
the program is ill-formed because the lookup set is empty ([[basic.lookup]](basic.lookup "6.5 Name lookup"))[.](#expr.delete-8.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[9](#expr.delete-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6534)
|
||
|
||
The deallocation function to be called is selected as follows:
|
||
|
||
- [(9.1)](#expr.delete-9.1)
|
||
|
||
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[.](#expr.delete-9.1.sentence-1)
|
||
|
||
- [(9.2)](#expr.delete-9.2)
|
||
|
||
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[.](#expr.delete-9.2.sentence-1)
|
||
If any preferred functions are found,
|
||
all non-preferred functions are eliminated from further consideration[.](#expr.delete-9.2.sentence-2)
|
||
|
||
- [(9.3)](#expr.delete-9.3)
|
||
|
||
If exactly one function remains,
|
||
that function is selected and the selection process terminates[.](#expr.delete-9.3.sentence-1)
|
||
|
||
- [(9.4)](#expr.delete-9.4)
|
||
|
||
If the deallocation functions belong to a class scope,
|
||
the one without a parameter of type std::size_t is selected[.](#expr.delete-9.4.sentence-1)
|
||
|
||
- [(9.5)](#expr.delete-9.5)
|
||
|
||
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[.](#expr.delete-9.5.sentence-1)
|
||
|
||
- [(9.6)](#expr.delete-9.6)
|
||
|
||
Otherwise, it is unspecified
|
||
whether a deallocation function with a parameter of type std::size_t is selected[.](#expr.delete-9.6.sentence-1)
|
||
|
||
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*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]") appears[.](#expr.delete-9.sentence-2)
|
||
|
||
[10](#expr.delete-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6569)
|
||
|
||
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[.](#expr.delete-10.sentence-1)
|
||
|
||
[*Note [6](#expr.delete-note-6)*:
|
||
|
||
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[.](#expr.delete-10.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
For an array delete expression,
|
||
the deleted object is
|
||
the array object[.](#expr.delete-10.sentence-3)
|
||
|
||
When a [*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]") 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]](#expr.new "7.6.2.8 New")) in an array delete expression,
|
||
as its first argument[.](#expr.delete-10.sentence-4)
|
||
|
||
[*Note [7](#expr.delete-note-7)*:
|
||
|
||
Any cv-qualifiers in the type of the deleted object
|
||
are ignored when forming this argument[.](#expr.delete-10.sentence-5)
|
||
|
||
â *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[.](#expr.delete-10.sentence-6)
|
||
|
||
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[.](#expr.delete-10.sentence-7)
|
||
|
||
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[.](#expr.delete-10.sentence-8)
|
||
|
||
[*Note [8](#expr.delete-note-8)*:
|
||
|
||
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.single "17.6.3.2 Single-object forms"), [[new.delete.array]](new.delete.array "17.6.3.3 Array forms"))[.](#expr.delete-10.sentence-9)
|
||
|
||
â *end note*]
|
||
|
||
[61)](#footnote-61)[61)](#footnoteref-61)
|
||
|
||
A[*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") with a [*lambda-introducer*](expr.prim.lambda.general#nt:lambda-introducer "7.5.6.1 General [expr.prim.lambda.general]") that consists of empty square brackets can follow the delete keyword
|
||
if the [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") is enclosed in parentheses[.](#footnote-61.sentence-1)
|
||
|
||
[62)](#footnote-62)[62)](#footnoteref-62)
|
||
|
||
For nonzero-length
|
||
arrays, this is the same as a pointer to the first
|
||
element of the array created by that [*new-expression*](#nt:new-expression "7.6.2.8 New [expr.new]")[.](#footnote-62.sentence-1)
|
||
|
||
Zero-length arrays do not have a first element[.](#footnote-62.sentence-2)
|
||
|
||
#### [7.6.2.10](#expr.reflect) The reflection operator [[expr.reflect]](expr.reflect)
|
||
|
||
[reflect-expression:](#nt:reflect-expression "7.6.2.10 The reflection operator [expr.reflect]")
|
||
^^ ::
|
||
^^ [*reflection-name*](#nt:reflection-name "7.6.2.10 The reflection operator [expr.reflect]")
|
||
^^ [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]")
|
||
^^ [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]")
|
||
|
||
[reflection-name:](#nt:reflection-name "7.6.2.10 The reflection operator [expr.reflect]")
|
||
[*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")opt [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]")
|
||
[*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") template [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]")
|
||
|
||
[1](#expr.reflect-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6637)
|
||
|
||
The unary ^^ operator,
|
||
called the [*reflection operator*](#def:operator,reflection "7.6.2.10 The reflection operator [expr.reflect]"),
|
||
yields a prvalue of type std::meta::info ([[basic.fundamental]](basic.fundamental "6.9.2 Fundamental types"))[.](#expr.reflect-1.sentence-1)
|
||
|
||
[*Note [1](#expr.reflect-note-1)*:
|
||
|
||
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-expression*](#nt:reflect-expression "7.6.2.10 The reflection operator [expr.reflect]")*s*[.](#expr.reflect-1.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[2](#expr.reflect-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6648)
|
||
|
||
The component names of a [*reflection-name*](#nt:reflection-name "7.6.2.10 The reflection operator [expr.reflect]") are those of its [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") (if any) and
|
||
its [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]")[.](#expr.reflect-2.sentence-1)
|
||
|
||
The terminal name of a [*reflection-name*](#nt:reflection-name "7.6.2.10 The reflection operator [expr.reflect]") of the form[*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") template [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") shall denote a template[.](#expr.reflect-2.sentence-2)
|
||
|
||
[3](#expr.reflect-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6656)
|
||
|
||
A [*reflect-expression*](#nt:reflect-expression "7.6.2.10 The reflection operator [expr.reflect]") is parsed as
|
||
the longest possible sequence of tokens
|
||
that could syntactically form a [*reflect-expression*](#nt:reflect-expression "7.6.2.10 The reflection operator [expr.reflect]")[.](#expr.reflect-3.sentence-1)
|
||
|
||
An unparenthesized [*reflect-expression*](#nt:reflect-expression "7.6.2.10 The reflection operator [expr.reflect]") that represents a template shall not be followed by <[.](#expr.reflect-3.sentence-2)
|
||
|
||
[*Example [1](#expr.reflect-example-1)*: static_assert(std::meta::is_type(^^int())); // ^^ applies to the type-id int()template<bool> struct X {};consteval bool operator<(std::meta::info, X<false>) { return false; }consteval void g(std::meta::info r, X<false> xv) { r == ^^int && true; // error: ^^ applies to the [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") int&& 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*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]")^^X < xv; // error: [*reflect-expression*](#nt:reflect-expression "7.6.2.10 The reflection operator [expr.reflect]") that represents a template is followed by <(^^X) < xv; // OK^^X<true> < xv; // OK} â *end example*]
|
||
|
||
[4](#expr.reflect-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6680)
|
||
|
||
A [*reflect-expression*](#nt:reflect-expression "7.6.2.10 The reflection operator [expr.reflect]") of the form ^^:: represents the global namespace[.](#expr.reflect-4.sentence-1)
|
||
|
||
[5](#expr.reflect-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6684)
|
||
|
||
If a [*reflect-expression*](#nt:reflect-expression "7.6.2.10 The reflection operator [expr.reflect]") R matches
|
||
the form ^^[*reflection-name*](#nt:reflection-name "7.6.2.10 The reflection operator [expr.reflect]"),
|
||
it is interpreted as such;
|
||
the [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") is looked up and
|
||
the representation of R is determined as follows:
|
||
|
||
- [(5.1)](#expr.reflect-5.1)
|
||
|
||
If lookup finds a declaration
|
||
that replaced a [*using-declarator*](namespace.udecl#nt:using-declarator "9.10 The using declaration [namespace.udecl]") during a single search ([[basic.lookup.general]](basic.lookup.general "6.5.1 General"), [[namespace.udecl]](namespace.udecl "9.10 The using declaration")),R is ill-formed[.](#expr.reflect-5.1.sentence-1)
|
||
[*Example [2](#expr.reflect-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-declarator*](namespace.udecl#nt:using-declarator "9.10 The using declaration [namespace.udecl]")struct C : virtual B { struct S {}; };struct D : virtual B, C {};
|
||
D::S s; // OK, names C::S per [[class.member.lookup]](class.member.lookup "6.5.2 Member name lookup")constexpr std::meta::info r2 = ^^D::S; // OK, result C::S not found through [*using-declarator*](namespace.udecl#nt:using-declarator "9.10 The using declaration [namespace.udecl]") â *end example*]
|
||
|
||
- [(5.2)](#expr.reflect-5.2)
|
||
|
||
Otherwise, if lookup finds a namespace alias ([[namespace.alias]](namespace.alias "9.9.3 Namespace alias")),R represents that namespace alias[.](#expr.reflect-5.2.sentence-1)
|
||
For any other [*namespace-name*](namespace.def.general#nt:namespace-name "9.9.2.1 General [namespace.def.general]"),R represents the denoted namespace[.](#expr.reflect-5.2.sentence-2)
|
||
|
||
- [(5.3)](#expr.reflect-5.3)
|
||
|
||
Otherwise, if lookup finds a namespace ([[basic.namespace]](basic.namespace "9.9 Namespaces")),R represents that namespace[.](#expr.reflect-5.3.sentence-1)
|
||
|
||
- [(5.4)](#expr.reflect-5.4)
|
||
|
||
Otherwise, if lookup finds a concept ([[temp.concept]](temp.concept "13.7.9 Concept definitions")),R represents the denoted concept[.](#expr.reflect-5.4.sentence-1)
|
||
|
||
- [(5.5)](#expr.reflect-5.5)
|
||
|
||
Otherwise, if lookup finds a template ([[temp.names]](temp.names "13.3 Names of template specializations")),
|
||
the representation of R is determined as follows:
|
||
* [(5.5.1)](#expr.reflect-5.5.1)
|
||
|
||
If lookup finds an injected-class-name ([[class.pre]](class.pre "11.1 Preamble")), then:
|
||
+
|
||
[(5.5.1.1)](#expr.reflect-5.5.1.1)
|
||
If the [*reflection-name*](#nt:reflection-name "7.6.2.10 The reflection operator [expr.reflect]") is of the form[*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") template [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]"),
|
||
then R represents the class template named by the injected-class-name[.](#expr.reflect-5.5.1.1.sentence-1)
|
||
|
||
+
|
||
[(5.5.1.2)](#expr.reflect-5.5.1.2)
|
||
Otherwise, the injected-class-name shall be unambiguous
|
||
when considered as a [*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]") andR represents the class template specialization so named[.](#expr.reflect-5.5.1.2.sentence-1)
|
||
|
||
* [(5.5.2)](#expr.reflect-5.5.2)
|
||
|
||
Otherwise, if lookup finds an overload set,
|
||
that overload set shall contain only
|
||
declarations of a unique function template F;R represents F[.](#expr.reflect-5.5.2.sentence-1)
|
||
|
||
* [(5.5.3)](#expr.reflect-5.5.3)
|
||
|
||
Otherwise, if lookup finds
|
||
a class template, variable template, or alias template,R represents that template[.](#expr.reflect-5.5.3.sentence-1)
|
||
[*Note [2](#expr.reflect-note-2)*:
|
||
Lookup never finds a partial or explicit specialization[.](#expr.reflect-5.5.3.sentence-2)
|
||
â *end note*]
|
||
|
||
- [(5.6)](#expr.reflect-5.6)
|
||
|
||
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[.](#expr.reflect-5.6.sentence-1)
|
||
|
||
- [(5.7)](#expr.reflect-5.7)
|
||
|
||
Otherwise, if lookup finds a class or an enumeration,R represents the denoted type[.](#expr.reflect-5.7.sentence-1)
|
||
|
||
- [(5.8)](#expr.reflect-5.8)
|
||
|
||
Otherwise, if lookup finds a class member of an anonymous union ([[class.union.anon]](class.union.anon "11.5.2 Anonymous unions")), R represents that class member[.](#expr.reflect-5.8.sentence-1)
|
||
|
||
- [(5.9)](#expr.reflect-5.9)
|
||
|
||
Otherwise,
|
||
the [*reflection-name*](#nt:reflection-name "7.6.2.10 The reflection operator [expr.reflect]") shall be an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") I and R is ^^I (see below)[.](#expr.reflect-5.9.sentence-1)
|
||
|
||
[6](#expr.reflect-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6764)
|
||
|
||
A [*reflect-expression*](#nt:reflect-expression "7.6.2.10 The reflection operator [expr.reflect]") R of the form^^[*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") represents an entity determined as follows:
|
||
|
||
- [(6.1)](#expr.reflect-6.1)
|
||
|
||
If the [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") designates
|
||
a placeholder type ([[dcl.spec.auto.general]](dcl.spec.auto.general "9.2.9.7.1 General")),R is ill-formed[.](#expr.reflect-6.1.sentence-1)
|
||
|
||
- [(6.2)](#expr.reflect-6.2)
|
||
|
||
Otherwise, if the [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") names a type alias
|
||
that is a specialization of an alias template ([[temp.alias]](temp.alias "13.7.8 Alias templates")),R represents that type alias[.](#expr.reflect-6.2.sentence-1)
|
||
|
||
- [(6.3)](#expr.reflect-6.3)
|
||
|
||
Otherwise, R represents the type denoted by the [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]")[.](#expr.reflect-6.3.sentence-1)
|
||
|
||
[7](#expr.reflect-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6781)
|
||
|
||
A [*reflect-expression*](#nt:reflect-expression "7.6.2.10 The reflection operator [expr.reflect]") R of the form^^[*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") represents an entity determined as follows:
|
||
|
||
- [(7.1)](#expr.reflect-7.1)
|
||
|
||
If the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") denotes
|
||
* [(7.1.1)](#expr.reflect-7.1.1)
|
||
|
||
a variable declared by
|
||
an [*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") ([[expr.prim.lambda.capture]](expr.prim.lambda.capture "7.5.6.3 Captures")),
|
||
|
||
* [(7.1.2)](#expr.reflect-7.1.2)
|
||
|
||
a function-local predefined variable ([[dcl.fct.def.general]](dcl.fct.def.general "9.6.1 General")),
|
||
|
||
* [(7.1.3)](#expr.reflect-7.1.3)
|
||
|
||
a local parameter introduced by
|
||
a [*requires-expression*](expr.prim.req.general#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") ([[expr.prim.req]](expr.prim.req "7.5.8 Requires expressions")), or
|
||
|
||
* [(7.1.4)](#expr.reflect-7.1.4)
|
||
|
||
a local entity E ([[basic.pre]](basic.pre "6.1 Preamble")) for which a lambda scope intervenes
|
||
between the point at which E was introduced and R,
|
||
|
||
then R is ill-formed[.](#expr.reflect-7.1.sentence-1)
|
||
|
||
- [(7.2)](#expr.reflect-7.2)
|
||
|
||
Otherwise, if the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") denotes an overload set S,
|
||
overload resolution for the expression &S with no target
|
||
shall select a unique function ([[over.over]](over.over "12.3 Address of an overload set"));R represents that function[.](#expr.reflect-7.2.sentence-1)
|
||
|
||
- [(7.3)](#expr.reflect-7.3)
|
||
|
||
Otherwise, if the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") denotes
|
||
a variable, structured binding, enumerator, or non-static data member,R represents that entity[.](#expr.reflect-7.3.sentence-1)
|
||
|
||
- [(7.4)](#expr.reflect-7.4)
|
||
|
||
Otherwise, R is ill-formed[.](#expr.reflect-7.4.sentence-1)
|
||
[*Note [3](#expr.reflect-note-3)*:
|
||
This includes [*unqualified-id*](expr.prim.id.unqual#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]")*s* that name a constant template parameter and[*pack-index-expression*](expr.prim.pack.index#nt:pack-index-expression "7.5.5.4 Pack indexing expression [expr.prim.pack.index]")*s*[.](#expr.reflect-7.4.sentence-2)
|
||
â *end note*]
|
||
|
||
The [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") of
|
||
a [*reflect-expression*](#nt:reflect-expression "7.6.2.10 The reflection operator [expr.reflect]") is an unevaluated operand ([[expr.context]](expr.context "7.2.3 Context dependence"))[.](#expr.reflect-7.sentence-2)
|
||
|
||
[*Example [3](#expr.reflect-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 {static constexpr std::meta::info r = ^^T; using type = T;};static_assert(S<int>::r == ^^int);static_assert(^^S<int>::type != ^^int);
|
||
|
||
typedef struct X {} Y;typedef struct 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]](basic.lookup.general "6.5.1 General")) â *end example*]
|