Init
This commit is contained in:
136
cppdraft/expr/add.md
Normal file
136
cppdraft/expr/add.md
Normal file
@@ -0,0 +1,136 @@
|
||||
[expr.add]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.add)
|
||||
|
||||
### 7.6.6 Additive operators [expr.add]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7108)
|
||||
|
||||
The additive operators + and - group left-to-right[.](#1.sentence-1)
|
||||
|
||||
Each operand shall be a prvalue[.](#1.sentence-2)
|
||||
|
||||
If both operands have arithmetic or unscoped enumeration type,
|
||||
the usual arithmetic conversions ([[expr.arith.conv]](expr.arith.conv "7.4 Usual arithmetic conversions")) are performed[.](#1.sentence-3)
|
||||
|
||||
Otherwise, if one operand has arithmetic or unscoped enumeration type,
|
||||
integral promotion is applied ([[conv.prom]](conv.prom "7.3.7 Integral promotions")) to that operand[.](#1.sentence-4)
|
||||
|
||||
A converted or promoted operand is used in place of
|
||||
the corresponding original operand for the remainder of this section[.](#1.sentence-5)
|
||||
|
||||
[additive-expression:](#nt:additive-expression "7.6.6 Additive operators [expr.add]")
|
||||
[*multiplicative-expression*](expr.mul#nt:multiplicative-expression "7.6.5 Multiplicative operators [expr.mul]")
|
||||
[*additive-expression*](#nt:additive-expression "7.6.6 Additive operators [expr.add]") + [*multiplicative-expression*](expr.mul#nt:multiplicative-expression "7.6.5 Multiplicative operators [expr.mul]")
|
||||
[*additive-expression*](#nt:additive-expression "7.6.6 Additive operators [expr.add]") - [*multiplicative-expression*](expr.mul#nt:multiplicative-expression "7.6.5 Multiplicative operators [expr.mul]")
|
||||
|
||||
For addition, either both operands shall have arithmetic
|
||||
type, or one operand shall be a pointer to a completely-defined object
|
||||
type and the other shall have integral type[.](#1.sentence-6)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7137)
|
||||
|
||||
For subtraction, one of the following shall hold:
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
both operands have arithmetic type; or
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
both operands are pointers to cv-qualified or cv-unqualified
|
||||
versions of the same completely-defined object type; or
|
||||
|
||||
- [(2.3)](#2.3)
|
||||
|
||||
the left operand is a pointer to a completely-defined object type
|
||||
and the right operand has integral type[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7151)
|
||||
|
||||
The result of the binary + operator is the sum of the operands[.](#3.sentence-1)
|
||||
|
||||
The result of the binary - operator is the difference resulting
|
||||
from the subtraction of the second operand from the first[.](#3.sentence-2)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7156)
|
||||
|
||||
When an expression J that has integral type
|
||||
is added to or subtracted from an expression P of pointer type,
|
||||
the result has the type of P[.](#4.sentence-1)
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
If P evaluates to a null pointer value andJ evaluates to 0, the result is a null pointer value[.](#4.1.sentence-1)
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
Otherwise, if P points to a (possibly-hypothetical) array element i of an array object x with n elements ([[dcl.array]](dcl.array "9.3.4.5 Arrays")),[64](#footnote-64 "As specified in [basic.compound], an object that is not an array element is considered to belong to a single-element array for this purpose and a pointer past the last element of an array of n elements is considered to be equivalent to a pointer to a hypothetical array element n for this purpose.") the expressions P + J and J + P (where J has the value j)
|
||||
point to the (possibly-hypothetical) array elementi+j of x if 0â¤i+jâ¤n and the expression P - J points to the (possibly-hypothetical) array elementiâj of x if 0â¤iâjâ¤n[.](#4.2.sentence-1)
|
||||
|
||||
- [(4.3)](#4.3)
|
||||
|
||||
Otherwise, the behavior is undefined[.](#4.3.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
Adding a value other than 0 or 1 to a pointer to a base class subobject, a member subobject,
|
||||
or a complete object results in undefined behavior[.](#4.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7189)
|
||||
|
||||
When two pointer expressions P and Q are subtracted,
|
||||
the type of the result is an implementation-defined signed
|
||||
integral type; this type shall be the same type that is named bystd::ptrdiff_t in the [<cstddef>](cstddef.syn#header:%3ccstddef%3e "17.2.1 Header <cstddef> synopsis [cstddef.syn]") header ([[support.types.layout]](support.types.layout "17.2.4 Sizes, alignments, and offsets"))[.](#5.sentence-1)
|
||||
|
||||
- [(5.1)](#5.1)
|
||||
|
||||
If P and Q both evaluate to null pointer values,
|
||||
the result is 0[.](#5.1.sentence-1)
|
||||
|
||||
- [(5.2)](#5.2)
|
||||
|
||||
Otherwise, if P and Q point to, respectively,
|
||||
array elements i and j of the same array object x,
|
||||
the expression P - Q has the value iâj[.](#5.2.sentence-1)
|
||||
[*Note [2](#note-2)*:
|
||||
If the value iâj is not in the range of representable values
|
||||
of type std::ptrdiff_t,
|
||||
the behavior is undefined ([[expr.pre]](expr.pre "7.1 Preamble"))[.](#5.2.sentence-2)
|
||||
â *end note*]
|
||||
|
||||
- [(5.3)](#5.3)
|
||||
|
||||
Otherwise, the behavior is undefined[.](#5.3.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7215)
|
||||
|
||||
For addition or subtraction, if the expressions P or Q have
|
||||
type âpointer to cv Tâ, where T and the array element type
|
||||
are not [similar](conv.qual#def:similar_types "7.3.6 Qualification conversions [conv.qual]"), the behavior is undefined[.](#6.sentence-1)
|
||||
|
||||
[*Example [1](#example-1)*: int arr[5] = {1, 2, 3, 4, 5};unsigned int *p = reinterpret_cast<unsigned int*>(arr + 1);unsigned int k = *p; // OK, value of k is 2 ([[conv.lval]](conv.lval "7.3.2 Lvalue-to-rvalue conversion"))unsigned int *q = p + 1; // undefined behavior: p points to an int, not an unsigned int object â *end example*]
|
||||
|
||||
[64)](#footnote-64)[64)](#footnoteref-64)
|
||||
|
||||
As specified in [[basic.compound]](basic.compound "6.9.4 Compound types"),
|
||||
an object that is not an array element
|
||||
is considered to belong to a single-element array for this purpose and
|
||||
a pointer past the last element of an array of n elements
|
||||
is considered to be equivalent to a pointer to a hypothetical array elementn for this purpose[.](#footnote-64.sentence-1)
|
||||
44
cppdraft/expr/alignof.md
Normal file
44
cppdraft/expr/alignof.md
Normal file
@@ -0,0 +1,44 @@
|
||||
[expr.alignof]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.alignof)
|
||||
|
||||
### 7.6.2 Unary expressions [[expr.unary]](expr.unary#expr.alignof)
|
||||
|
||||
#### 7.6.2.6 Alignof [expr.alignof]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5700)
|
||||
|
||||
An alignof expression yields the alignment requirement
|
||||
of its operand type[.](#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[.](#1.sentence-2)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5708)
|
||||
|
||||
The result is a prvalue of type std::size_t[.](#2.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
An alignof expression
|
||||
is an integral constant expression ([[expr.const]](expr.const "7.7 Constant expressions"))[.](#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"))[.](#2.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#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[.](#3.sentence-1)
|
||||
|
||||
When alignof is applied to an array type, the result is the alignment of the
|
||||
element type[.](#3.sentence-2)
|
||||
105
cppdraft/expr/arith/conv.md
Normal file
105
cppdraft/expr/arith/conv.md
Normal file
@@ -0,0 +1,105 @@
|
||||
[expr.arith.conv]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.4 Usual arithmetic conversions [expr.arith.conv]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1161)
|
||||
|
||||
Many binary operators that expect operands of arithmetic or enumeration
|
||||
type cause conversions and yield result types in a similar way[.](#1.sentence-1)
|
||||
|
||||
The
|
||||
purpose is to yield a common type, which is also the type of the result[.](#1.sentence-2)
|
||||
|
||||
This pattern is called the [*usual arithmetic conversions*](#def:conversion,usual_arithmetic "7.4 Usual arithmetic conversions [expr.arith.conv]"),
|
||||
which are defined as follows:
|
||||
|
||||
- [(1.1)](#1.1)
|
||||
|
||||
The lvalue-to-rvalue conversion ([[conv.lval]](conv.lval "7.3.2 Lvalue-to-rvalue conversion"))
|
||||
is applied to each operand and
|
||||
the resulting prvalues are used in place of the original operands
|
||||
for the remainder of this section[.](#1.1.sentence-1)
|
||||
|
||||
- [(1.2)](#1.2)
|
||||
|
||||
If either operand is of scoped enumeration type ([[dcl.enum]](dcl.enum "9.8.1 Enumeration declarations")), no conversions
|
||||
are performed; if the other operand does not have the same type, the expression is
|
||||
ill-formed[.](#1.2.sentence-1)
|
||||
|
||||
- [(1.3)](#1.3)
|
||||
|
||||
Otherwise, if one operand is of enumeration type and the other operand is
|
||||
of a different enumeration type or a floating-point type, the expression is
|
||||
ill-formed[.](#1.3.sentence-1)
|
||||
|
||||
- [(1.4)](#1.4)
|
||||
|
||||
Otherwise, if either operand is of floating-point type,
|
||||
the following rules are applied:
|
||||
* [(1.4.1)](#1.4.1)
|
||||
|
||||
If both operands have the same type, no further conversion is performed[.](#1.4.1.sentence-1)
|
||||
|
||||
* [(1.4.2)](#1.4.2)
|
||||
|
||||
Otherwise, if one of the operands is of a non-floating-point type,
|
||||
that operand is converted to the type of
|
||||
the operand with the floating-point type[.](#1.4.2.sentence-1)
|
||||
|
||||
* [(1.4.3)](#1.4.3)
|
||||
|
||||
Otherwise, if the floating-point conversion ranks ([[conv.rank]](conv.rank "6.9.6 Conversion ranks")) of
|
||||
the types of the operands are ordered but not equal,
|
||||
then the operand of the type with the lesser floating-point conversion rank
|
||||
is converted to the type of the other operand[.](#1.4.3.sentence-1)
|
||||
|
||||
* [(1.4.4)](#1.4.4)
|
||||
|
||||
Otherwise, if the floating-point conversion ranks of the types of
|
||||
the operands are equal,
|
||||
then the operand with the lesser floating-point conversion subrank ([[conv.rank]](conv.rank "6.9.6 Conversion ranks"))
|
||||
is converted to the type of the other operand[.](#1.4.4.sentence-1)
|
||||
|
||||
* [(1.4.5)](#1.4.5)
|
||||
|
||||
Otherwise, the expression is ill-formed[.](#1.4.5.sentence-1)
|
||||
|
||||
- [(1.5)](#1.5)
|
||||
|
||||
Otherwise, each operand is converted to a common type C[.](#1.5.sentence-1)
|
||||
The integral promotion rules ([[conv.prom]](conv.prom "7.3.7 Integral promotions")) are used
|
||||
to determine a type T1 and type T2 for each operand[.](#1.5.sentence-2)[47](#footnote-47 "As a consequence, operands of type bool, char8_t, char16_t, char32_t, wchar_t, or of enumeration type are converted to some integral type.")
|
||||
Then the following rules are applied to determine C:
|
||||
* [(1.5.1)](#1.5.1)
|
||||
|
||||
If T1 and T2 are the same type, C is that type[.](#1.5.1.sentence-1)
|
||||
|
||||
* [(1.5.2)](#1.5.2)
|
||||
|
||||
Otherwise, if T1 and T2 are both signed integer types or
|
||||
are both unsigned integer types,C is the type with greater rank[.](#1.5.2.sentence-1)
|
||||
|
||||
* [(1.5.3)](#1.5.3)
|
||||
|
||||
Otherwise, let U be the unsigned integer type andS be the signed integer type[.](#1.5.3.sentence-1)
|
||||
|
||||
+
|
||||
[(1.5.3.1)](#1.5.3.1)
|
||||
If U has rank greater than or equal to the rank of S,C is U[.](#1.5.3.1.sentence-1)
|
||||
|
||||
+
|
||||
[(1.5.3.2)](#1.5.3.2)
|
||||
Otherwise, if S can represent all of the values of U,C is S[.](#1.5.3.2.sentence-1)
|
||||
|
||||
+
|
||||
[(1.5.3.3)](#1.5.3.3)
|
||||
Otherwise,C is the unsigned integer type corresponding to S[.](#1.5.3.3.sentence-1)
|
||||
|
||||
[47)](#footnote-47)[47)](#footnoteref-47)
|
||||
|
||||
As a consequence, operands of type bool, char8_t, char16_t,char32_t, wchar_t, or of enumeration type are converted
|
||||
to some integral type[.](#footnote-47.sentence-1)
|
||||
145
cppdraft/expr/assign.md
Normal file
145
cppdraft/expr/assign.md
Normal file
@@ -0,0 +1,145 @@
|
||||
[expr.assign]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.assign)
|
||||
|
||||
### 7.6.19 Assignment and compound assignment operators [expr.assign]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8067)
|
||||
|
||||
The assignment operator (=) and the compound assignment
|
||||
operators all group right-to-left[.](#1.sentence-1)
|
||||
|
||||
All
|
||||
require a modifiable lvalue as their left operand; their result is an lvalue
|
||||
of the type of the left operand, referring to the left operand[.](#1.sentence-2)
|
||||
|
||||
The result in all cases is a bit-field if
|
||||
the left operand is a bit-field[.](#1.sentence-3)
|
||||
|
||||
In all cases, the assignment is
|
||||
sequenced after thevalue computation of the right and left operands,
|
||||
and before the
|
||||
value computation of the assignment expression[.](#1.sentence-4)
|
||||
|
||||
The right operand is sequenced before the left operand[.](#1.sentence-5)
|
||||
|
||||
With
|
||||
respect to an indeterminately-sequenced function call, the operation of
|
||||
a compound assignment is a single evaluation[.](#1.sentence-6)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
Therefore, a function call cannot intervene between the
|
||||
lvalue-to-rvalue conversion and the side effect associated with any
|
||||
single compound assignment operator[.](#1.sentence-7)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[assignment-expression:](#nt:assignment-expression "7.6.19 Assignment and compound assignment operators [expr.assign]")
|
||||
[*conditional-expression*](expr.cond#nt:conditional-expression "7.6.16 Conditional operator [expr.cond]")
|
||||
[*yield-expression*](expr.yield#nt:yield-expression "7.6.17 Yielding a value [expr.yield]")
|
||||
[*throw-expression*](expr.throw#nt:throw-expression "7.6.18 Throwing an exception [expr.throw]")
|
||||
[*logical-or-expression*](expr.log.or#nt:logical-or-expression "7.6.15 Logical OR operator [expr.log.or]") [*assignment-operator*](#nt:assignment-operator "7.6.19 Assignment and compound assignment operators [expr.assign]") [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1 General [dcl.init.general]")
|
||||
|
||||
[assignment-operator:](#nt:assignment-operator "7.6.19 Assignment and compound assignment operators [expr.assign]") one of
|
||||
= *= /= %= += -= >>= <<= &= ^= |=
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8115)
|
||||
|
||||
In simple assignment (=),
|
||||
let V be the result of the right operand;
|
||||
the object referred to by the left operand is
|
||||
modified ([[defns.access]](defns.access "3.1 access")) by replacing its value
|
||||
with V or,
|
||||
if the object is of integer type,
|
||||
with the value congruent ([[basic.fundamental]](basic.fundamental "6.9.2 Fundamental types")) to V[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8124)
|
||||
|
||||
If the right operand is an expression, it is implicitly[converted](conv "7.3 Standard conversions [conv]") to the cv-unqualified type of the left
|
||||
operand[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8130)
|
||||
|
||||
When the left operand of an assignment operator
|
||||
is a bit-field that cannot represent the value of the expression, the
|
||||
resulting value of the bit-field isimplementation-defined[.](#4.sentence-1)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8137)
|
||||
|
||||
An assignment whose left operand is of
|
||||
a volatile-qualified type is deprecated ([[depr.volatile.type]](depr.volatile.type "D.4 Deprecated volatile types"))
|
||||
unless the (possibly parenthesized) assignment is a discarded-value expression or
|
||||
an [unevaluated operand](expr.context#def:unevaluated_operand "7.2.3 Context dependence [expr.context]")[.](#5.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8143)
|
||||
|
||||
The behavior of an expression of the form E1 *op*= E2 is equivalent to E1 = E1 *op* E2 except
|
||||
that E1 is evaluated only once[.](#6.sentence-1)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
The object designated by E1 is accessed twice[.](#6.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
For += and -=,E1 shall either have arithmetic type or be a pointer to a
|
||||
possibly cv-qualified completely-defined object type[.](#6.sentence-3)
|
||||
|
||||
In all other
|
||||
cases, E1 shall have arithmetic type[.](#6.sentence-4)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8155)
|
||||
|
||||
If the value being stored in an object is read via another object that
|
||||
overlaps in any way the storage of the first object, then the overlap shall be
|
||||
exact and the two objects shall have the same type, otherwise the behavior is
|
||||
undefined[.](#7.sentence-1)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
This restriction applies to the relationship
|
||||
between the left and right sides of the assignment operation; it is not a
|
||||
statement about how the target of the assignment can be aliased in general[.](#7.sentence-2)
|
||||
|
||||
See [[basic.lval]](basic.lval "7.2.1 Value category")[.](#7.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8167)
|
||||
|
||||
A [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]") B may appear on the right-hand side of
|
||||
|
||||
- [(8.1)](#8.1)
|
||||
|
||||
an assignment to a scalar of type T, in which case B shall have at most a single element[.](#8.1.sentence-1)
|
||||
The meaning of x = B is x = t,
|
||||
where t is an invented temporary variable
|
||||
declared and initialized as T t = B[.](#8.1.sentence-2)
|
||||
|
||||
- [(8.2)](#8.2)
|
||||
|
||||
an assignment to an object of class type, in which case B is passed as the argument to the assignment operator function selected by
|
||||
overload resolution ([[over.assign]](over.assign "12.4.3.2 Simple assignment"), [[over.match]](over.match "12.2 Overload resolution"))[.](#8.2.sentence-1)
|
||||
|
||||
[*Example [1](#example-1)*: complex<double> z;
|
||||
z = { 1,2 }; // meaning z.operator=({1,2}) z += { 1, 2 }; // meaning z.operator+=({1,2})int a, b;
|
||||
a = b = { 1 }; // meaning a=b=1; a = { 1 } = b; // syntax error â *end example*]
|
||||
188
cppdraft/expr/await.md
Normal file
188
cppdraft/expr/await.md
Normal file
@@ -0,0 +1,188 @@
|
||||
[expr.await]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.await)
|
||||
|
||||
### 7.6.2 Unary expressions [[expr.unary]](expr.unary#expr.await)
|
||||
|
||||
#### 7.6.2.4 Await [expr.await]
|
||||
|
||||
[1](#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[.](#1.sentence-1)
|
||||
|
||||
Suspending the evaluation of a coroutine
|
||||
transfers control to its caller or resumer[.](#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](#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"))[.](#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]")[.](#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"))[.](#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[.](#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"))[.](#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[.](#2.sentence-6)
|
||||
|
||||
[3](#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)](#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[.](#3.1.sentence-1)
|
||||
|
||||
- [(3.2)](#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"))[.](#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]")[.](#3.2.sentence-2)
|
||||
|
||||
- [(3.3)](#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"))[.](#3.3.sentence-1)
|
||||
If overload resolution is ambiguous,
|
||||
the program is ill-formed[.](#3.3.sentence-2)
|
||||
If no viable functions are found, *o* is *a*[.](#3.3.sentence-3)
|
||||
Otherwise, *o* is a call to the selected function
|
||||
with the argument *a*[.](#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[.](#3.3.sentence-5)
|
||||
|
||||
- [(3.4)](#3.4)
|
||||
|
||||
*e* is an lvalue
|
||||
referring to the result of evaluating
|
||||
the (possibly-converted) *o*[.](#3.4.sentence-1)
|
||||
|
||||
- [(3.5)](#3.5)
|
||||
|
||||
*h* is an object of typestd::coroutine_handle<P> referring to the enclosing coroutine[.](#3.5.sentence-1)
|
||||
|
||||
- [(3.6)](#3.6)
|
||||
|
||||
*await-ready* is the expression*e*.await_ready(),
|
||||
contextually converted to bool[.](#3.6.sentence-1)
|
||||
|
||||
- [(3.7)](#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[.](#3.7.sentence-1)
|
||||
|
||||
- [(3.8)](#3.8)
|
||||
|
||||
*await-resume* is the expression*e*.await_resume()[.](#3.8.sentence-1)
|
||||
|
||||
[4](#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[.](#4.sentence-1)
|
||||
|
||||
[5](#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)](#5.1)
|
||||
|
||||
If the result of *await-ready* is false,
|
||||
the coroutine is considered suspended[.](#5.1.sentence-1)
|
||||
Then:
|
||||
* [(5.1.1)](#5.1.1)
|
||||
|
||||
If the type of *await-suspend* is std::coroutine_handle<Z>,*await-suspend*.resume() is evaluated[.](#5.1.1.sentence-1)
|
||||
[*Note [1](#note-1)*:
|
||||
This resumes the coroutine referred to
|
||||
by the result of *await-suspend*[.](#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"))[.](#5.1.1.sentence-3)
|
||||
â *end note*]
|
||||
|
||||
* [(5.1.2)](#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[.](#5.1.2.sentence-1)
|
||||
|
||||
* [(5.1.3)](#5.1.3)
|
||||
|
||||
Otherwise, *await-suspend* is evaluated[.](#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"))[.](#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"))[.](#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]")[.](#5.1.sentence-5)
|
||||
|
||||
- [(5.2)](#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]")[.](#5.2.sentence-1)
|
||||
|
||||
[*Note [2](#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"))[.](#5.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5565)
|
||||
|
||||
[*Example [1](#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*]
|
||||
31
cppdraft/expr/bit/and.md
Normal file
31
cppdraft/expr/bit/and.md
Normal file
@@ -0,0 +1,31 @@
|
||||
[expr.bit.and]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.bit.and)
|
||||
|
||||
### 7.6.11 Bitwise AND operator [expr.bit.and]
|
||||
|
||||
[and-expression:](#nt:and-expression "7.6.11 Bitwise AND operator [expr.bit.and]")
|
||||
[*equality-expression*](expr.eq#nt:equality-expression "7.6.10 Equality operators [expr.eq]")
|
||||
[*and-expression*](#nt:and-expression "7.6.11 Bitwise AND operator [expr.bit.and]") & [*equality-expression*](expr.eq#nt:equality-expression "7.6.10 Equality operators [expr.eq]")
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7668)
|
||||
|
||||
The & operator groups left-to-right[.](#1.sentence-1)
|
||||
|
||||
The operands shall be of integral or unscoped enumeration type[.](#1.sentence-2)
|
||||
|
||||
The usual arithmetic conversions ([[expr.arith.conv]](expr.arith.conv "7.4 Usual arithmetic conversions")) are performed[.](#1.sentence-3)
|
||||
|
||||
Given the coefficients xi and yi of the base-2 representation ([[basic.fundamental]](basic.fundamental "6.9.2 Fundamental types"))
|
||||
of the converted operands x and y,
|
||||
the coefficient ri of the base-2 representation of the result r is 1 if both xi and yi are 1, and 0 otherwise[.](#1.sentence-4)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
The result is the bitwise and function of the operands[.](#1.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
377
cppdraft/expr/call.md
Normal file
377
cppdraft/expr/call.md
Normal file
@@ -0,0 +1,377 @@
|
||||
[expr.call]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.call)
|
||||
|
||||
### 7.6.1 Postfix expressions [[expr.post]](expr.post#expr.call)
|
||||
|
||||
#### 7.6.1.3 Function call [expr.call]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3749)
|
||||
|
||||
A function call is a postfix expression followed by parentheses
|
||||
containing a possibly empty, comma-separated list of[*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1 General [dcl.init.general]")*s* which
|
||||
constitute the arguments to the function[.](#1.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
If the postfix expression is a function or member function name,
|
||||
the appropriate function and the validity of the call
|
||||
are determined according to the rules in [[over.match]](over.match "12.2 Overload resolution")[.](#1.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
The postfix expression shall
|
||||
have function type or function pointer type[.](#1.sentence-3)
|
||||
|
||||
For a call to a non-member function or to a static member function,
|
||||
the postfix expression shall be either an lvalue that refers to a
|
||||
function (in which case the function-to-pointer standard
|
||||
conversion ([[conv.func]](conv.func "7.3.4 Function-to-pointer conversion")) is suppressed on the postfix expression),
|
||||
or a prvalue of function pointer type[.](#1.sentence-4)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3770)
|
||||
|
||||
If the selected
|
||||
function is non-virtual, or if the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") in the class
|
||||
member access expression is a [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]"), that function is
|
||||
called[.](#2.sentence-1)
|
||||
|
||||
Otherwise, its [final overrider](class.virtual#def:final_overrider "11.7.3 Virtual functions [class.virtual]") in the dynamic type
|
||||
of the object expression is called; such a call is referred to as a[*virtual function call*](#def:function,virtual_function_call "7.6.1.3 Function call [expr.call]")[.](#2.sentence-2)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
The dynamic type is the type of the object referred to by the
|
||||
current value of the object expression[.](#2.sentence-3)
|
||||
|
||||
[[class.cdtor]](class.cdtor "11.9.5 Construction and destruction") describes the
|
||||
behavior of virtual function calls when the object expression
|
||||
refers to
|
||||
an object under construction or destruction[.](#2.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3785)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
If a function or member function name is used, and [name
|
||||
lookup](basic.lookup "6.5 Name lookup [basic.lookup]") does not find a declaration of that name,
|
||||
the program is ill-formed[.](#3.sentence-1)
|
||||
|
||||
No function is implicitly declared by such a
|
||||
call[.](#3.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3793)
|
||||
|
||||
If the [*postfix-expression*](expr.post.general#nt:postfix-expression "7.6.1.1 General [expr.post.general]") names
|
||||
a destructor or pseudo-destructor ([[expr.prim.id.dtor]](expr.prim.id.dtor "7.5.5.5 Destruction")),
|
||||
the type of the function call expression is void; otherwise, the
|
||||
type of the function call expression is the return type of the
|
||||
statically chosen function (i.e., ignoring the virtual keyword),
|
||||
even if the type of the function actually called is different[.](#4.sentence-1)
|
||||
|
||||
If the [*postfix-expression*](expr.post.general#nt:postfix-expression "7.6.1.1 General [expr.post.general]") names a pseudo-destructor
|
||||
(in which case the [*postfix-expression*](expr.post.general#nt:postfix-expression "7.6.1.1 General [expr.post.general]") is a possibly-parenthesized class member access),
|
||||
the function call destroys
|
||||
the object of scalar type
|
||||
denoted by the object expression
|
||||
of the class member access ([[expr.ref]](expr.ref "7.6.1.5 Class member access"), [[basic.life]](basic.life "6.8.4 Lifetime"))[.](#4.sentence-2)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3809)
|
||||
|
||||
A type Tcall is[*call-compatible*](#def:call-compatible "7.6.1.3 Function call [expr.call]") with a function type Tfunc if Tcall is the same type as Tfunc or
|
||||
if the type âpointer to Tfuncâ can be
|
||||
converted to type âpointer to Tcallâ
|
||||
via a function pointer conversion ([[conv.fctptr]](conv.fctptr "7.3.14 Function pointer conversions"))[.](#5.sentence-1)
|
||||
|
||||
Calling a function through an
|
||||
expression whose function type
|
||||
is not call-compatible with the
|
||||
type of the called function's
|
||||
definition results in undefined behavior[.](#5.sentence-2)
|
||||
|
||||
[*Note [4](#note-4)*:
|
||||
|
||||
This requirement allows the case
|
||||
when the expression has the type of a
|
||||
potentially-throwing function, but the called function has
|
||||
a non-throwing exception specification,
|
||||
and the function types are otherwise the same[.](#5.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3829)
|
||||
|
||||
When a function is called, each parameter ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")) is
|
||||
initialized ([[dcl.init]](dcl.init "9.5 Initializers"), [[class.copy.ctor]](class.copy.ctor "11.4.5.3 Copy/move constructors")) with
|
||||
its corresponding argument,
|
||||
and each precondition assertion of the function
|
||||
is evaluated ([[dcl.contract.func]](dcl.contract.func "9.4.1 General"))[.](#6.sentence-1)
|
||||
|
||||
If the function is an explicit object member function and
|
||||
there is an implied object argument ([[over.call.func]](over.call.func "12.2.2.2.2 Call to designated function")),
|
||||
the list of provided arguments is preceded by the implied object argument
|
||||
for the purposes of this correspondence[.](#6.sentence-2)
|
||||
|
||||
If there is no corresponding argument,
|
||||
the default argument for the parameter is used[.](#6.sentence-3)
|
||||
|
||||
[*Example [1](#example-1)*: template<typename ...T> int f(int n = 0, T ...t);int x = f<int>(); // error: no argument for second function parameter â *end example*]
|
||||
|
||||
If the function is an implicit object member
|
||||
function,
|
||||
the object expression of the class member access shall be a glvalue and
|
||||
the implicit object parameter of the function ([[over.match.funcs]](over.match.funcs "12.2.2 Candidate functions and argument lists"))
|
||||
is initialized with that glvalue,
|
||||
converted as if by an [explicit type conversion](expr.cast "7.6.3 Explicit type conversion (cast notation) [expr.cast]")[.](#6.sentence-4)
|
||||
|
||||
[*Note [5](#note-5)*:
|
||||
|
||||
There is no access or ambiguity checking on this conversion; the access
|
||||
checking and disambiguation are done as part of the (possibly implicit)
|
||||
class member access operator[.](#6.sentence-5)
|
||||
|
||||
See [[class.member.lookup]](class.member.lookup "6.5.2 Member name lookup"), [[class.access.base]](class.access.base "11.8.3 Accessibility of base classes and base class members"),
|
||||
and [[expr.ref]](expr.ref "7.6.1.5 Class member access")[.](#6.sentence-6)
|
||||
|
||||
â *end note*]
|
||||
|
||||
When a function is called, the type of any parameter
|
||||
shall not be a class type that is either incomplete or abstract[.](#6.sentence-7)
|
||||
|
||||
[*Note [6](#note-6)*:
|
||||
|
||||
This still allows a parameter to be a pointer or reference to such
|
||||
a type[.](#6.sentence-8)
|
||||
|
||||
However, it prevents a passed-by-value parameter
|
||||
to have an incomplete or abstract class type[.](#6.sentence-9)
|
||||
|
||||
â *end note*]
|
||||
|
||||
It is implementation-defined
|
||||
whether a parameter is destroyed
|
||||
when the function in which it is defined exits ([[stmt.return]](stmt.return "8.8.4 The return statement"), [[except.ctor]](except.ctor "14.3 Stack unwinding"), [[expr.await]](expr.await "7.6.2.4 Await"))
|
||||
or at the end of the enclosing full-expression;
|
||||
parameters are always destroyed in the reverse order of their construction[.](#6.sentence-10)
|
||||
|
||||
The initialization and destruction of each parameter occurs
|
||||
within the context of the full-expression ([[intro.execution]](intro.execution "6.10.1 Sequential execution"))
|
||||
where the function call appears[.](#6.sentence-11)
|
||||
|
||||
[*Example [2](#example-2)*:
|
||||
|
||||
The access ([[class.access.general]](class.access.general "11.8.1 General")) of the
|
||||
constructor, conversion functions, or destructor is
|
||||
checked at the point of call[.](#6.sentence-12)
|
||||
|
||||
If a constructor
|
||||
or destructor for a function parameter throws an exception,
|
||||
any [*function-try-block*](except.pre#nt:function-try-block "14.1 Preamble [except.pre]") ([[except.pre]](except.pre "14.1 Preamble"))
|
||||
of the called function
|
||||
with a handler that can handle the exception
|
||||
is not considered[.](#6.sentence-13)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3890)
|
||||
|
||||
The [*postfix-expression*](expr.post.general#nt:postfix-expression "7.6.1.1 General [expr.post.general]") is sequenced before
|
||||
each [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") in the [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") and any default argument[.](#7.sentence-1)
|
||||
|
||||
The initialization of a parameter or,
|
||||
if the implementation introduces any temporary objects
|
||||
to hold the values of function parameters ([[class.temporary]](class.temporary "6.8.7 Temporary objects")),
|
||||
the initialization of those temporaries,
|
||||
including every associated value computation and side effect,
|
||||
is indeterminately sequenced with respect to that of any other parameter[.](#7.sentence-2)
|
||||
|
||||
These evaluations are
|
||||
sequenced before
|
||||
the evaluation of the precondition assertions of the function,
|
||||
which are evaluated in sequence ([[dcl.contract.func]](dcl.contract.func "9.4.1 General"))[.](#7.sentence-3)
|
||||
|
||||
For any temporaries
|
||||
introduced to hold the values of function parameters,
|
||||
the initialization of the parameter objects from those temporaries
|
||||
is indeterminately sequenced with respect to
|
||||
the evaluation of each precondition assertion[.](#7.sentence-4)
|
||||
|
||||
[*Note [7](#note-7)*:
|
||||
|
||||
All side effects of
|
||||
argument evaluations are sequenced before the function is
|
||||
entered (see [[intro.execution]](intro.execution "6.10.1 Sequential execution"))[.](#7.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [3](#example-3)*: void f() { std::string s = "but I have heard it works even if you don't believe in it";
|
||||
s.replace(0, 4, "").replace(s.find("even"), 4, "only").replace(s.find(" don't"), 6, "");
|
||||
assert(s == "I have heard it works only if you believe in it"); // OK} â *end example*]
|
||||
|
||||
[*Note [8](#note-8)*:
|
||||
|
||||
If an operator function is invoked
|
||||
using operator notation,
|
||||
argument evaluation is sequenced
|
||||
as specified for the built-in operator;
|
||||
see [[over.match.oper]](over.match.oper "12.2.2.3 Operators in expressions")[.](#7.sentence-6)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [4](#example-4)*: struct S { S(int);};int operator<<(S, int);int i, j;int x = S(i=1) << (i=2);int y = operator<<(S(j=1), j=2);
|
||||
|
||||
After performing the initializations,
|
||||
the value of i is 2 (see [[expr.shift]](expr.shift "7.6.7 Shift operators")),
|
||||
but it is unspecified whether the value of j is 1 or 2[.](#7.sentence-7)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3948)
|
||||
|
||||
The result of a function call is the result of the possibly-converted operand
|
||||
of the return statement ([[stmt.return]](stmt.return "8.8.4 The return statement"))
|
||||
that transferred control out of the called function (if any),
|
||||
except in a virtual function call if the return type of the
|
||||
final overrider is different from the return type of the statically
|
||||
chosen function, the value returned from the final overrider is
|
||||
converted to the return type of the statically chosen function[.](#8.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3957)
|
||||
|
||||
When the called function exits normally ([[stmt.return]](stmt.return "8.8.4 The return statement"), [[expr.await]](expr.await "7.6.2.4 Await")),
|
||||
all postcondition assertions of the function
|
||||
are evaluated in sequence ([[dcl.contract.func]](dcl.contract.func "9.4.1 General"))[.](#9.sentence-1)
|
||||
|
||||
If the implementation introduces any temporary objects
|
||||
to hold the result value as specified in [[class.temporary]](class.temporary "6.8.7 Temporary objects"),
|
||||
the evaluation of each postcondition assertion
|
||||
is indeterminately sequenced with respect to
|
||||
the initialization of any of those temporaries or the result object[.](#9.sentence-2)
|
||||
|
||||
These evaluations, in turn, are sequenced before
|
||||
the destruction of any function parameters[.](#9.sentence-3)
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3969)
|
||||
|
||||
[*Note [9](#note-9)*:
|
||||
|
||||
A function can change the values of its non-const parameters, but these
|
||||
changes cannot affect the values of the arguments except where a
|
||||
parameter is of a reference type ([[dcl.ref]](dcl.ref "9.3.4.3 References")); if the reference is to
|
||||
a const-qualified type, const_cast needs to be used to
|
||||
cast away the constness in order to modify the argument's value[.](#10.sentence-1)
|
||||
|
||||
Where a
|
||||
parameter is of const reference type a temporary object is
|
||||
introduced if
|
||||
needed ([[dcl.type]](dcl.type "9.2.9 Type specifiers"), [[lex.literal]](lex.literal "5.13 Literals"), [[lex.string]](lex.string "5.13.5 String literals"), [[dcl.array]](dcl.array "9.3.4.5 Arrays"), [[class.temporary]](class.temporary "6.8.7 Temporary objects"))[.](#10.sentence-2)
|
||||
|
||||
In addition, it is possible to modify the values of non-constant objects through
|
||||
pointer parameters[.](#10.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3989)
|
||||
|
||||
A function can be declared to accept fewer arguments (by declaring [default
|
||||
arguments](dcl.fct.default "9.3.4.7 Default arguments [dcl.fct.default]")) or more arguments (by using the ellipsis,..., or a function parameter pack ([[dcl.fct]](dcl.fct "9.3.4.6 Functions"))) than the number of
|
||||
parameters in the [function definition](dcl.fct.def "9.6 Function definitions [dcl.fct.def]")[.](#11.sentence-1)
|
||||
|
||||
[*Note [10](#note-10)*:
|
||||
|
||||
This implies that, except where the ellipsis (...) or a function
|
||||
parameter pack is used, a parameter is available for each argument[.](#11.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4001)
|
||||
|
||||
When there is no parameter for a given argument, the argument is passed
|
||||
in such a way that the receiving function can obtain the value of the
|
||||
argument by invoking va_arg ([[support.runtime]](support.runtime "17.14 Other runtime support"))[.](#12.sentence-1)
|
||||
|
||||
[*Note [11](#note-11)*:
|
||||
|
||||
This paragraph does not apply to arguments passed to a function parameter pack[.](#12.sentence-2)
|
||||
|
||||
Function parameter packs are expanded during template instantiation ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates")),
|
||||
thus each such argument has a corresponding parameter when a function template
|
||||
specialization is actually called[.](#12.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
The[lvalue-to-rvalue](conv.lval "7.3.2 Lvalue-to-rvalue conversion [conv.lval]"), [array-to-pointer](conv.array "7.3.3 Array-to-pointer conversion [conv.array]"),
|
||||
and [function-to-pointer](conv.func "7.3.4 Function-to-pointer conversion [conv.func]") standard conversions are
|
||||
performed on the argument expression[.](#12.sentence-4)
|
||||
|
||||
An argument that has type cv std::nullptr_t is converted
|
||||
to type void* ([[conv.ptr]](conv.ptr "7.3.12 Pointer conversions"))[.](#12.sentence-5)
|
||||
|
||||
After these conversions, if the
|
||||
argument does not have arithmetic, enumeration, pointer, pointer-to-member,
|
||||
or class type, the program is ill-formed[.](#12.sentence-6)
|
||||
|
||||
Passing a potentially-evaluated argument
|
||||
of a scoped enumeration type ([[dcl.enum]](dcl.enum "9.8.1 Enumeration declarations")) or
|
||||
of a class type ([[class]](class "11 Classes")) having
|
||||
an eligible non-trivial copy constructor ([[special]](special "11.4.4 Special member functions"), [[class.copy.ctor]](class.copy.ctor "11.4.5.3 Copy/move constructors")),
|
||||
an eligible non-trivial move constructor, or
|
||||
a non-trivial destructor ([[class.dtor]](class.dtor "11.4.7 Destructors")),
|
||||
with no corresponding parameter, is conditionally-supported withimplementation-defined semantics[.](#12.sentence-7)
|
||||
|
||||
If the argument has
|
||||
integral or enumeration type that is subject to the [integral
|
||||
promotions](conv.prom "7.3.7 Integral promotions [conv.prom]"), or a floating-point type that is subject to the[floating-point promotion](conv.fpprom "7.3.8 Floating-point promotion [conv.fpprom]"), the value of the argument is converted to the
|
||||
promoted type before the call[.](#12.sentence-8)
|
||||
|
||||
These promotions are referred to as
|
||||
the [*default argument promotions*](#def:promotion,default_argument_promotion "7.6.1.3 Function call [expr.call]")[.](#12.sentence-9)
|
||||
|
||||
[13](#13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4035)
|
||||
|
||||
Recursive calls are permitted, except to the [main function](basic.start.main "6.10.3.1 main function [basic.start.main]")[.](#13.sentence-1)
|
||||
|
||||
[14](#14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4040)
|
||||
|
||||
A function call is an lvalue
|
||||
if the result type is an lvalue reference type or an rvalue reference to function type,
|
||||
an xvalue if the result type is an rvalue reference to object type, and a prvalue
|
||||
otherwise[.](#14.sentence-1)
|
||||
|
||||
If it is a non-void prvalue,
|
||||
the type of the function call expression shall be complete,
|
||||
except as specified in [[dcl.type.decltype]](dcl.type.decltype "9.2.9.6 Decltype specifiers")[.](#14.sentence-2)
|
||||
131
cppdraft/expr/cast.md
Normal file
131
cppdraft/expr/cast.md
Normal file
@@ -0,0 +1,131 @@
|
||||
[expr.cast]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.cast)
|
||||
|
||||
### 7.6.3 Explicit type conversion (cast notation) [expr.cast]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6850)
|
||||
|
||||
The result of the expression (T) [*cast-expression*](#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]") is
|
||||
of type T[.](#1.sentence-1)
|
||||
|
||||
The result is an lvalue if T is an lvalue
|
||||
reference type or an rvalue reference to function type and an xvalue if T is an rvalue reference to object type; otherwise the result is a prvalue[.](#1.sentence-2)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
If T is a non-class type that is cv-qualified, the[*cv-qualifier*](dcl.decl.general#nt:cv-qualifier "9.3.1 General [dcl.decl.general]")*s* are discarded when determining the type of the
|
||||
resulting prvalue; see [[expr.prop]](expr.prop "7.2 Properties of expressions")[.](#1.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6861)
|
||||
|
||||
An explicit type conversion can be expressed using functional
|
||||
notation ([[expr.type.conv]](expr.type.conv "7.6.1.4 Explicit type conversion (functional notation)")), a type conversion operator
|
||||
(dynamic_cast, static_cast, reinterpret_cast,const_cast), or the [*cast*](#def:cast) notation[.](#2.sentence-1)
|
||||
|
||||
[cast-expression:](#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]")
|
||||
[*unary-expression*](expr.unary.general#nt:unary-expression "7.6.2.1 General [expr.unary.general]")
|
||||
( [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") ) [*cast-expression*](#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]")
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6873)
|
||||
|
||||
Any type conversion not mentioned below and not explicitly defined by
|
||||
the user ([[class.conv]](class.conv "11.4.8 Conversions")) is ill-formed[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6877)
|
||||
|
||||
The conversions performed by
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
a const_cast ([[expr.const.cast]](expr.const.cast "7.6.1.11 Const cast")),
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
a static_cast ([[expr.static.cast]](expr.static.cast "7.6.1.9 Static cast")),
|
||||
|
||||
- [(4.3)](#4.3)
|
||||
|
||||
a static_cast followed by a const_cast,
|
||||
|
||||
- [(4.4)](#4.4)
|
||||
|
||||
a reinterpret_cast ([[expr.reinterpret.cast]](expr.reinterpret.cast "7.6.1.10 Reinterpret cast")), or
|
||||
|
||||
- [(4.5)](#4.5)
|
||||
|
||||
a reinterpret_cast followed by a const_cast,
|
||||
|
||||
can be performed using the cast notation of explicit type conversion[.](#4.sentence-1)
|
||||
|
||||
The same semantic restrictions and behaviors apply, with the exception
|
||||
that in performing a static_cast in the following situations the
|
||||
conversion is valid even if the base class is inaccessible:
|
||||
|
||||
- [(4.6)](#4.6)
|
||||
|
||||
a pointer to an object of derived class type or an lvalue or
|
||||
rvalue of derived class type may be explicitly converted to a pointer or
|
||||
reference to an unambiguous base class type, respectively;
|
||||
|
||||
- [(4.7)](#4.7)
|
||||
|
||||
a pointer to member of derived class type may be explicitly
|
||||
converted to a pointer to member of an unambiguous non-virtual base
|
||||
class type;
|
||||
|
||||
- [(4.8)](#4.8)
|
||||
|
||||
a pointer to an object of an unambiguous non-virtual base class
|
||||
type, a glvalue of an unambiguous non-virtual base class type,
|
||||
or a pointer to member of an unambiguous non-virtual base class type may
|
||||
be explicitly converted to a pointer, a reference, or a pointer to
|
||||
member of a derived class type, respectively[.](#4.sentence-2)
|
||||
|
||||
If a conversion can be interpreted in more than one of the ways listed
|
||||
above, the interpretation that appears first in the list is used, even
|
||||
if a cast resulting from that interpretation is ill-formed[.](#4.sentence-3)
|
||||
|
||||
If astatic_cast followed by a const_cast is used and
|
||||
the conversion can be interpreted in more than one way as such,
|
||||
the conversion is
|
||||
ill-formed[.](#4.sentence-4)
|
||||
|
||||
[*Example [1](#example-1)*: struct A { };struct I1 : A { };struct I2 : A { };struct D : I1, I2 { };
|
||||
A* foo( D* p ) {return (A*)( p ); // ill-formed static_cast interpretation}int*** ptr = 0;auto t = (int const*const*const*)ptr; // OK, const_cast interpretationstruct S {operator const int*(); operator volatile int*();};int *p = (int*)S(); // error: two possible interpretations using static_cast followed by const_cast â *end example*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6937)
|
||||
|
||||
The operand of a cast using the cast notation can be a prvalue of type
|
||||
âpointer to incomplete class typeâ[.](#5.sentence-1)
|
||||
|
||||
The destination type of a cast
|
||||
using the cast notation can be âpointer to incomplete class typeâ[.](#5.sentence-2)
|
||||
|
||||
If
|
||||
both the operand and destination types are class types and one or both
|
||||
are incomplete, it is unspecified whether the static_cast or thereinterpret_cast interpretation is used, even if there is an
|
||||
inheritance relationship between the two classes[.](#5.sentence-3)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
For example, if the classes were defined later in the translation unit,
|
||||
a multi-pass compiler could validly interpret a cast between
|
||||
pointers to the classes as if the class types were complete at the point
|
||||
of the cast[.](#5.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
50
cppdraft/expr/comma.md
Normal file
50
cppdraft/expr/comma.md
Normal file
@@ -0,0 +1,50 @@
|
||||
[expr.comma]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.comma)
|
||||
|
||||
### 7.6.20 Comma operator [expr.comma]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8202)
|
||||
|
||||
The comma operator groups left-to-right[.](#1.sentence-1)
|
||||
|
||||
[expression:](#nt:expression "7.6.20 Comma operator [expr.comma]")
|
||||
[*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment and compound assignment operators [expr.assign]")
|
||||
[*expression*](#nt:expression "7.6.20 Comma operator [expr.comma]") , [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment and compound assignment operators [expr.assign]")
|
||||
|
||||
A pair of expressions separated by a comma is evaluated left-to-right;
|
||||
the left expression is
|
||||
a [discarded-value expression](expr.prop#def:discarded-value_expression "7.2 Properties of expressions [expr.prop]")[.](#1.sentence-2)
|
||||
|
||||
The left expression is sequenced before
|
||||
the right expression ([[intro.execution]](intro.execution "6.10.1 Sequential execution"))[.](#1.sentence-3)
|
||||
|
||||
The type and value of the
|
||||
result are the type and value of the right operand; the result is of the same
|
||||
value category as its right operand, and is a bit-field if its
|
||||
right operand is a bit-field[.](#1.sentence-4)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8222)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
In contexts where the comma token is given special meaning
|
||||
(e.g., function calls ([[expr.call]](expr.call "7.6.1.3 Function call")),
|
||||
subscript expressions ([[expr.sub]](expr.sub "7.6.1.2 Subscripting")),
|
||||
lists of initializers ([[dcl.init]](dcl.init "9.5 Initializers")),
|
||||
or [*template-argument-list*](temp.names#nt:template-argument-list "13.3 Names of template specializations [temp.names]")*s* ([[temp.names]](temp.names "13.3 Names of template specializations"))),
|
||||
the comma operator as described in this subclause can appear only in parentheses[.](#2.sentence-1)
|
||||
|
||||
[*Example [1](#example-1)*:
|
||||
|
||||
f(a, (t=3, t+2), c); has three arguments, the second of which has the value5[.](#2.sentence-2)
|
||||
|
||||
â *end example*]
|
||||
|
||||
â *end note*]
|
||||
5036
cppdraft/expr/compound.md
Normal file
5036
cppdraft/expr/compound.md
Normal file
File diff suppressed because it is too large
Load Diff
224
cppdraft/expr/cond.md
Normal file
224
cppdraft/expr/cond.md
Normal file
@@ -0,0 +1,224 @@
|
||||
[expr.cond]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.cond)
|
||||
|
||||
### 7.6.16 Conditional operator [expr.cond]
|
||||
|
||||
[conditional-expression:](#nt:conditional-expression "7.6.16 Conditional operator [expr.cond]")
|
||||
[*logical-or-expression*](expr.log.or#nt:logical-or-expression "7.6.15 Logical OR operator [expr.log.or]")
|
||||
[*logical-or-expression*](expr.log.or#nt:logical-or-expression "7.6.15 Logical OR operator [expr.log.or]") ? [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") : [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment and compound assignment operators [expr.assign]")
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7798)
|
||||
|
||||
Conditional expressions group right-to-left[.](#1.sentence-1)
|
||||
|
||||
The first expression is
|
||||
contextually converted to bool ([[conv]](conv "7.3 Standard conversions"))[.](#1.sentence-2)
|
||||
|
||||
It is
|
||||
evaluated and if it is true, the result of the conditional
|
||||
expression is the value of the second expression, otherwise that of the
|
||||
third expression[.](#1.sentence-3)
|
||||
|
||||
Only one of the second and third expressions is
|
||||
evaluated[.](#1.sentence-4)
|
||||
|
||||
The first expression is sequenced before
|
||||
the second or third expression ([[intro.execution]](intro.execution "6.10.1 Sequential execution"))[.](#1.sentence-5)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7809)
|
||||
|
||||
If either the second or the third operand has type void,
|
||||
one of the following shall hold:
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
The second or the third operand (but not both) is a (possibly
|
||||
parenthesized) [*throw-expression*](expr.throw#nt:throw-expression "7.6.18 Throwing an exception [expr.throw]") ([[expr.throw]](expr.throw "7.6.18 Throwing an exception")); the result
|
||||
is of the type and value category of the other[.](#2.1.sentence-1)
|
||||
The [*conditional-expression*](#nt:conditional-expression "7.6.16 Conditional operator [expr.cond]") is a bit-field if that operand is a bit-field[.](#2.1.sentence-2)
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
Both the second and the third operands have type void; the
|
||||
result is of type void and is a prvalue[.](#2.2.sentence-1)
|
||||
[*Note [1](#note-1)*:
|
||||
This
|
||||
includes the case where both operands are [*throw-expression*](expr.throw#nt:throw-expression "7.6.18 Throwing an exception [expr.throw]")*s*[.](#2.2.sentence-2)
|
||||
â *end note*]
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7829)
|
||||
|
||||
Otherwise, if the second and third operand are glvalue bit-fields
|
||||
of the same value category and
|
||||
of types *cv1* T and *cv2* T, respectively,
|
||||
the operands are considered to be of type cv T for the remainder of this subclause,
|
||||
where cv is the union of *cv1* and *cv2*[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7837)
|
||||
|
||||
Otherwise, if the second and third operand have different types and
|
||||
either has (possibly cv-qualified) class type, or if both
|
||||
are glvalues of the same value category and the same type except for
|
||||
cv-qualification, an attempt is made to
|
||||
form an [implicit conversion sequence](over.best.ics "12.2.4.2 Implicit conversion sequences [over.best.ics]") from
|
||||
each of those operands to the type of the other[.](#4.sentence-1)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
Properties such as access, whether an operand is a bit-field, or whether
|
||||
a conversion function is deleted are ignored for that determination[.](#4.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
Attempts are made to form an implicit conversion sequence
|
||||
from an operand expression E1 of type T1 to a target type related to the type T2 of the operand expression E2 as follows:
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
If E2 is an lvalue, the target type is
|
||||
âlvalue reference to T2â,
|
||||
but an implicit conversion sequence can only be formed
|
||||
if the reference would bind directly ([[dcl.init.ref]](dcl.init.ref "9.5.4 References"))
|
||||
to a glvalue[.](#4.1.sentence-1)
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
If E2 is an xvalue, the target type is
|
||||
ârvalue reference to T2â,
|
||||
but an implicit conversion sequence can only be formed
|
||||
if the reference would bind directly[.](#4.2.sentence-1)
|
||||
|
||||
- [(4.3)](#4.3)
|
||||
|
||||
If E2 is a prvalue or if neither of the conversion sequences above can be
|
||||
formed and at least one of the operands has (possibly cv-qualified) class type:
|
||||
* [(4.3.1)](#4.3.1)
|
||||
|
||||
if T1 and T2 are the same class type
|
||||
(ignoring cv-qualification):
|
||||
+
|
||||
[(4.3.1.1)](#4.3.1.1)
|
||||
if T2 is at least as cv-qualified as T1,
|
||||
the target type is T2,
|
||||
|
||||
+
|
||||
[(4.3.1.2)](#4.3.1.2)
|
||||
otherwise, no conversion sequence is formed for this operand;
|
||||
|
||||
* [(4.3.2)](#4.3.2)
|
||||
|
||||
otherwise, if T2 is a base class of T1,
|
||||
the target type is *cv1* T2, where *cv1* denotes the cv-qualifiers of T1;
|
||||
|
||||
* [(4.3.3)](#4.3.3)
|
||||
|
||||
otherwise, the target type is the type that E2 would have
|
||||
after applying the[lvalue-to-rvalue](conv.lval "7.3.2 Lvalue-to-rvalue conversion [conv.lval]"),[array-to-pointer](conv.array "7.3.3 Array-to-pointer conversion [conv.array]"), and[function-to-pointer](conv.func "7.3.4 Function-to-pointer conversion [conv.func]") standard conversions[.](#4.3.sentence-1)
|
||||
|
||||
Using this process, it is determined whether an implicit conversion
|
||||
sequence can be formed from the second operand
|
||||
to the target type determined for the third operand, and vice versa,
|
||||
with the following outcome:
|
||||
|
||||
- [(4.4)](#4.4)
|
||||
|
||||
If both sequences can be formed, or one can be formed but it is the
|
||||
ambiguous conversion sequence, the program is ill-formed[.](#4.4.sentence-1)
|
||||
|
||||
- [(4.5)](#4.5)
|
||||
|
||||
If no conversion sequence can be formed, the operands are left unchanged
|
||||
and further checking is performed as described below[.](#4.5.sentence-1)
|
||||
|
||||
- [(4.6)](#4.6)
|
||||
|
||||
Otherwise, if exactly one conversion sequence can be formed,
|
||||
that conversion is applied to the chosen operand
|
||||
and the converted operand is used in place of the original operand for
|
||||
the remainder of this subclause[.](#4.6.sentence-1)
|
||||
[*Note [3](#note-3)*:
|
||||
The conversion might be ill-formed even if an implicit conversion
|
||||
sequence could be formed[.](#4.6.sentence-2)
|
||||
â *end note*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7909)
|
||||
|
||||
If the second and third operands are glvalues of the same value category
|
||||
and have the same type, the
|
||||
result is of that type and value category and it is a bit-field if the
|
||||
second or the third operand is a bit-field, or if both are bit-fields[.](#5.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7915)
|
||||
|
||||
Otherwise, the result is a prvalue[.](#6.sentence-1)
|
||||
|
||||
If the second and third operands do
|
||||
not have the same type, and either has (possibly cv-qualified) class
|
||||
type, overload resolution is used to determine the conversions (if any)
|
||||
to be applied to the operands ([[over.match.oper]](over.match.oper "12.2.2.3 Operators in expressions"), [[over.built]](over.built "12.5 Built-in operators"))[.](#6.sentence-2)
|
||||
|
||||
If the overload resolution fails, the program is ill-formed[.](#6.sentence-3)
|
||||
|
||||
Otherwise,
|
||||
the conversions thus determined are applied, and the converted operands
|
||||
are used in place of the original operands for the remainder of this
|
||||
subclause[.](#6.sentence-4)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7925)
|
||||
|
||||
[Array-to-pointer](conv.array "7.3.3 Array-to-pointer conversion [conv.array]") and [function-to-pointer](conv.func "7.3.4 Function-to-pointer conversion [conv.func]") standard conversions are
|
||||
performed on the second and third operands[.](#7.sentence-1)
|
||||
|
||||
After those conversions, one
|
||||
of the following shall hold:
|
||||
|
||||
- [(7.1)](#7.1)
|
||||
|
||||
The second and third operands have the same type; the result is of
|
||||
that type and the result is copy-initialized using the selected operand[.](#7.1.sentence-1)
|
||||
|
||||
- [(7.2)](#7.2)
|
||||
|
||||
The second and third operands have arithmetic or enumeration type;
|
||||
the [usual arithmetic conversions](expr.arith.conv "7.4 Usual arithmetic conversions [expr.arith.conv]") are performed to bring them to a common
|
||||
type, and the result is of that type[.](#7.2.sentence-1)
|
||||
|
||||
- [(7.3)](#7.3)
|
||||
|
||||
One or both of the second and third operands have pointer type;[lvalue-to-rvalue](conv.lval "7.3.2 Lvalue-to-rvalue conversion [conv.lval]"),[pointer](conv.ptr "7.3.12 Pointer conversions [conv.ptr]"),[function pointer](conv.fctptr "7.3.14 Function pointer conversions [conv.fctptr]"), and[qualification conversions](conv.qual "7.3.6 Qualification conversions [conv.qual]") are performed to bring them to their[composite pointer type](expr.type#def:composite_pointer_type "7.2.2 Type [expr.type]")[.](#7.3.sentence-1)
|
||||
The result is of the composite
|
||||
pointer type[.](#7.3.sentence-2)
|
||||
|
||||
- [(7.4)](#7.4)
|
||||
|
||||
One or both of the second and third operands have pointer-to-member type;
|
||||
lvalue-to-rvalue ([[conv.lval]](conv.lval "7.3.2 Lvalue-to-rvalue conversion")),
|
||||
pointer to member ([[conv.mem]](conv.mem "7.3.13 Pointer-to-member conversions")),
|
||||
function pointer ([[conv.fctptr]](conv.fctptr "7.3.14 Function pointer conversions")), and
|
||||
qualification conversions ([[conv.qual]](conv.qual "7.3.6 Qualification conversions"))
|
||||
are performed to bring them to their composite
|
||||
pointer type ([[expr.type]](expr.type "7.2.2 Type"))[.](#7.4.sentence-1)
|
||||
The result is of the composite pointer type[.](#7.4.sentence-2)
|
||||
|
||||
- [(7.5)](#7.5)
|
||||
|
||||
Both the second and third operands have type std::nullptr_t or one has
|
||||
that type and the other is a null pointer constant[.](#7.5.sentence-1)
|
||||
The result is of typestd::nullptr_t[.](#7.5.sentence-2)
|
||||
1120
cppdraft/expr/const.md
Normal file
1120
cppdraft/expr/const.md
Normal file
File diff suppressed because it is too large
Load Diff
136
cppdraft/expr/const/cast.md
Normal file
136
cppdraft/expr/const/cast.md
Normal file
@@ -0,0 +1,136 @@
|
||||
[expr.const.cast]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.const.cast)
|
||||
|
||||
### 7.6.1 Postfix expressions [[expr.post]](expr.post#expr.const.cast)
|
||||
|
||||
#### 7.6.1.11 Const cast [expr.const.cast]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5051)
|
||||
|
||||
The result of the expression const_cast<T>(v) is of typeT[.](#1.sentence-1)
|
||||
|
||||
If T is an lvalue reference to object type, the result is an
|
||||
lvalue;
|
||||
if T is an rvalue reference to object type, the result is an xvalue;
|
||||
otherwise, the result is a prvalue and the[lvalue-to-rvalue](conv.lval "7.3.2 Lvalue-to-rvalue conversion [conv.lval]"), [array-to-pointer](conv.array "7.3.3 Array-to-pointer conversion [conv.array]"),
|
||||
and [function-to-pointer](conv.func "7.3.4 Function-to-pointer conversion [conv.func]") standard conversions are
|
||||
performed on the expression v[.](#1.sentence-2)
|
||||
|
||||
The [temporary materialization conversion](conv.rval "7.3.5 Temporary materialization conversion [conv.rval]") is not
|
||||
performed on v, other than as specified below[.](#1.sentence-3)
|
||||
|
||||
Conversions that can be performed explicitly usingconst_cast are listed below[.](#1.sentence-4)
|
||||
|
||||
No other conversion shall be
|
||||
performed explicitly using const_cast[.](#1.sentence-5)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5068)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
Subject to the restrictions in this subclause, an expression can be cast
|
||||
to its own type using a const_cast operator[.](#2.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5074)
|
||||
|
||||
For two similar object pointer or pointer to data member typesT1 and T2 ([[conv.qual]](conv.qual "7.3.6 Qualification conversions")),
|
||||
a prvalue of type T1 can be explicitly
|
||||
converted to the type T2 using a const_cast if, considering the qualification-decompositions of both types,
|
||||
each P1i is the same as P2i for all i[.](#3.sentence-1)
|
||||
|
||||
If v is a null pointer or null member pointer,
|
||||
the result is a null pointer or null member pointer, respectively[.](#3.sentence-2)
|
||||
|
||||
Otherwise, the result points to or past the end of the same object, or
|
||||
points to the same member, respectively, as v[.](#3.sentence-3)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5086)
|
||||
|
||||
For two object types T1 and T2, if a pointer to T1 can
|
||||
be explicitly converted to the type âpointer to T2â using aconst_cast, then the following conversions can also be made:
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
an lvalue of type T1 can be explicitly converted to an lvalue
|
||||
of type T2 using the cast const_cast<T2&>;
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
a glvalue of type T1 can be explicitly converted to an xvalue
|
||||
of type T2 using the cast const_cast<T2&&>; and
|
||||
|
||||
- [(4.3)](#4.3)
|
||||
|
||||
if T1 is a class or array type,
|
||||
a prvalue of type T1 can be
|
||||
explicitly converted to an xvalue of type T2 using the castconst_cast<T2&&>[.](#4.sentence-1)
|
||||
The temporary materialization conversion is performed on v[.](#4.3.sentence-2)
|
||||
|
||||
The result refers to the same object as the (possibly converted) operand[.](#4.sentence-2)
|
||||
|
||||
[*Example [1](#example-1)*: typedef int *A[3]; // array of 3 pointer to inttypedef const int *const CA[3]; // array of 3 const pointer to const intauto &&r2 = const_cast<A&&>(CA{}); // OK, temporary materialization conversion is performed â *end example*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5114)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
Depending on the type of the object, a write operation through the
|
||||
pointer, lvalue or pointer to data member resulting from aconst_cast that casts away a const-qualifier[56](#footnote-56 "const_cast is not limited to conversions that cast away a const-qualifier.") can produce undefined behavior ([[dcl.type.cv]](dcl.type.cv "9.2.9.2 The cv-qualifiers"))[.](#5.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5127)
|
||||
|
||||
A conversion from a type T1 to a type T2[*casts away constness*](#def:casting_away_constness "7.6.1.11 Const cast [expr.const.cast]") if T1 and T2 are different,
|
||||
there is a qualification-decomposition ([[conv.qual]](conv.qual "7.3.6 Qualification conversions")) of T1 yielding *n* such thatT2 has a qualification-decomposition of the formcv20 P20 cv21 P21 ⯠cv2nâ1 P2nâ1 cv2n U2, and there is no qualification conversion that converts T1 tocv20 P10 cv21 P11 ⯠cv2nâ1 P1nâ1 cv2n U1[.](#6.sentence-1)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5143)
|
||||
|
||||
Casting from an lvalue of type T1 to an lvalue of typeT2 using an lvalue reference cast
|
||||
or casting from an expression of type T1 to an xvalue of type T2 using
|
||||
an rvalue reference cast
|
||||
casts away constness if a cast from a prvalue of type âpointer to T1â to the type âpointer toT2â casts away constness[.](#7.sentence-1)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5151)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
Some conversions which involve only changes in cv-qualification cannot
|
||||
be done using const_cast[.](#8.sentence-1)
|
||||
|
||||
For instance, conversions between
|
||||
pointers to functions are not covered because such conversions lead to
|
||||
values whose use causes undefined behavior[.](#8.sentence-2)
|
||||
|
||||
For the same reasons,
|
||||
conversions between pointers to member functions, and in particular, the
|
||||
conversion from a pointer to a const member function to a pointer to a
|
||||
non-const member function, are not covered[.](#8.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[56)](#footnote-56)[56)](#footnoteref-56)
|
||||
|
||||
const_cast is not limited to conversions that cast away a
|
||||
const-qualifier[.](#footnote-56.sentence-1)
|
||||
100
cppdraft/expr/context.md
Normal file
100
cppdraft/expr/context.md
Normal file
@@ -0,0 +1,100 @@
|
||||
[expr.context]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.2 Properties of expressions [[expr.prop]](expr.prop#expr.context)
|
||||
|
||||
### 7.2.3 Context dependence [expr.context]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L438)
|
||||
|
||||
In some contexts, [*unevaluated operands*](#def:unevaluated_operand "7.2.3 Context dependence [expr.context]") appear ([[expr.prim.req.simple]](expr.prim.req.simple "7.5.8.2 Simple requirements"), [[expr.prim.req.compound]](expr.prim.req.compound "7.5.8.4 Compound requirements"), [[expr.typeid]](expr.typeid "7.6.1.8 Type identification"), [[expr.sizeof]](expr.sizeof "7.6.2.5 Sizeof"), [[expr.unary.noexcept]](expr.unary.noexcept "7.6.2.7 noexcept operator"), [[expr.reflect]](expr.reflect "7.6.2.10 The reflection operator"), [[dcl.type.decltype]](dcl.type.decltype "9.2.9.6 Decltype specifiers"), [[temp.pre]](temp.pre "13.1 Preamble"), [[temp.concept]](temp.concept "13.7.9 Concept definitions"))[.](#1.sentence-1)
|
||||
|
||||
An unevaluated operand is not evaluated[.](#1.sentence-2)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
In an unevaluated operand, a non-static class member can be
|
||||
named ([[expr.prim.id]](expr.prim.id "7.5.5 Names")) and naming of objects or functions does not, by
|
||||
itself, require that a definition be provided ([[basic.def.odr]](basic.def.odr "6.3 One-definition rule"))[.](#1.sentence-3)
|
||||
|
||||
An unevaluated operand is considered a [full-expression](intro.execution#def:full-expression "6.10.1 Sequential execution [intro.execution]")[.](#1.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L458)
|
||||
|
||||
In some contexts, an expression only appears for its side effects[.](#2.sentence-1)
|
||||
|
||||
Such an
|
||||
expression is called a [*discarded-value expression*](#def:discarded-value_expression "7.2.3 Context dependence [expr.context]")[.](#2.sentence-2)
|
||||
|
||||
The [array-to-pointer](conv.array "7.3.3 Array-to-pointer conversion [conv.array]") and [function-to-pointer](conv.func "7.3.4 Function-to-pointer conversion [conv.func]") standard conversions are not
|
||||
applied[.](#2.sentence-3)
|
||||
|
||||
The [lvalue-to-rvalue](conv.lval "7.3.2 Lvalue-to-rvalue conversion [conv.lval]") conversion is applied
|
||||
if and only if
|
||||
the expression is a glvalue of volatile-qualified type and it is one of the
|
||||
following:
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
( [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") ), where[*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") is one of these expressions,
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
[*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") ([[expr.prim.id]](expr.prim.id "7.5.5 Names")),
|
||||
|
||||
- [(2.3)](#2.3)
|
||||
|
||||
[*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") ([[expr.prim.splice]](expr.prim.splice "7.5.9 Expression splicing")),
|
||||
|
||||
- [(2.4)](#2.4)
|
||||
|
||||
[subscripting](expr.sub "7.6.1.2 Subscripting [expr.sub]"),
|
||||
|
||||
- [(2.5)](#2.5)
|
||||
|
||||
[class member access](expr.ref "7.6.1.5 Class member access [expr.ref]"),
|
||||
|
||||
- [(2.6)](#2.6)
|
||||
|
||||
[indirection](expr.unary.op#def:indirection "7.6.2.2 Unary operators [expr.unary.op]"),
|
||||
|
||||
- [(2.7)](#2.7)
|
||||
|
||||
[pointer-to-member operation](expr.mptr.oper "7.6.4 Pointer-to-member operators [expr.mptr.oper]"),
|
||||
|
||||
- [(2.8)](#2.8)
|
||||
|
||||
[conditional expression](expr.cond "7.6.16 Conditional operator [expr.cond]") where both the second and the
|
||||
third operands are one of these expressions, or
|
||||
|
||||
- [(2.9)](#2.9)
|
||||
|
||||
[comma expression](expr.comma "7.6.20 Comma operator [expr.comma]") where the right operand is one of
|
||||
these expressions[.](#2.sentence-4)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
Using an overloaded operator causes a function call; the
|
||||
above covers only operators with built-in meaning[.](#2.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
The temporary materialization conversion ([[conv.rval]](conv.rval "7.3.5 Temporary materialization conversion")) is applied
|
||||
if the (possibly converted) expression is a prvalue of object type[.](#2.sentence-6)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
If the original expression is an lvalue of class type,
|
||||
it must have a volatile copy constructor to initialize the temporary object
|
||||
that is the result object of the temporary materialization conversion[.](#2.sentence-7)
|
||||
|
||||
â *end note*]
|
||||
|
||||
The expression is evaluated and its result (if any) is discarded[.](#2.sentence-8)
|
||||
331
cppdraft/expr/delete.md
Normal file
331
cppdraft/expr/delete.md
Normal file
@@ -0,0 +1,331 @@
|
||||
[expr.delete]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.delete)
|
||||
|
||||
### 7.6.2 Unary expressions [[expr.unary]](expr.unary#expr.delete)
|
||||
|
||||
#### 7.6.2.9 Delete [expr.delete]
|
||||
|
||||
[1](#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*](expr.new#nt:new-expression "7.6.2.8 New [expr.new]")[.](#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]")[.](#1.sentence-2)
|
||||
|
||||
Whenever the delete keyword is immediately followed by empty square
|
||||
brackets, it shall be interpreted as the second alternative[.](#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[.](#1.sentence-4)
|
||||
|
||||
Otherwise, it shall be a prvalue of pointer to object type[.](#1.sentence-5)
|
||||
|
||||
The [*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]") has typevoid[.](#1.sentence-6)
|
||||
|
||||
[2](#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*](expr.new#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*](expr.new#nt:new-expression "7.6.2.8 New [expr.new]")[.](#2.sentence-1)
|
||||
|
||||
If not, the behavior is undefined[.](#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*](expr.new#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"))[.](#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[.](#2.sentence-4)
|
||||
|
||||
[*Note [1](#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*](expr.new#nt:new-expression "7.6.2.8 New [expr.new]")[.](#2.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Note [2](#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]")[.](#2.sentence-6)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#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[.](#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[.](#3.sentence-2)
|
||||
|
||||
[4](#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[.](#4.sentence-1)
|
||||
|
||||
[5](#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[.](#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[.](#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"))[.](#5.sentence-3)
|
||||
|
||||
[6](#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)](#6.1)
|
||||
|
||||
If the allocation call for the [*new-expression*](expr.new#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]")[.](#6.1.sentence-1)
|
||||
The value returned from the
|
||||
allocation call of the [*new-expression*](expr.new#nt:new-expression "7.6.2.8 New [expr.new]") shall be passed as the
|
||||
first argument to the deallocation function[.](#6.1.sentence-2)
|
||||
|
||||
- [(6.2)](#6.2)
|
||||
|
||||
Otherwise, if the allocation was extended or was provided by extending the
|
||||
allocation of another [*new-expression*](expr.new#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*](expr.new#nt:new-expression "7.6.2.8 New [expr.new]") that had storage provided by the extended[*new-expression*](expr.new#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[.](#6.2.sentence-1)
|
||||
The value
|
||||
returned from the allocation call of the extended [*new-expression*](expr.new#nt:new-expression "7.6.2.8 New [expr.new]") shall be passed as the first argument to the deallocation function[.](#6.2.sentence-2)
|
||||
|
||||
- [(6.3)](#6.3)
|
||||
|
||||
Otherwise, the [*delete-expression*](#nt:delete-expression "7.6.2.9 Delete [expr.delete]") will not call a
|
||||
deallocation function[.](#6.3.sentence-1)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
The deallocation function is called regardless of whether the destructor
|
||||
for the object or some element of the array throws an exception[.](#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[.](#6.sentence-3)
|
||||
|
||||
[7](#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[.](#7.sentence-1)
|
||||
|
||||
[*Note [4](#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"))[.](#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"))[.](#7.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[8](#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)](#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"))[.](#8.1.sentence-1)
|
||||
|
||||
- [(8.2)](#8.2)
|
||||
|
||||
Otherwise,
|
||||
a search is performed for the deallocation function's name
|
||||
in the scope of T[.](#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[.](#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[.](#8.sentence-3)
|
||||
|
||||
[*Note [5](#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"))[.](#8.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6534)
|
||||
|
||||
The deallocation function to be called is selected as follows:
|
||||
|
||||
- [(9.1)](#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[.](#9.1.sentence-1)
|
||||
|
||||
- [(9.2)](#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[.](#9.2.sentence-1)
|
||||
If any preferred functions are found,
|
||||
all non-preferred functions are eliminated from further consideration[.](#9.2.sentence-2)
|
||||
|
||||
- [(9.3)](#9.3)
|
||||
|
||||
If exactly one function remains,
|
||||
that function is selected and the selection process terminates[.](#9.3.sentence-1)
|
||||
|
||||
- [(9.4)](#9.4)
|
||||
|
||||
If the deallocation functions belong to a class scope,
|
||||
the one without a parameter of type std::size_t is selected[.](#9.4.sentence-1)
|
||||
|
||||
- [(9.5)](#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[.](#9.5.sentence-1)
|
||||
|
||||
- [(9.6)](#9.6)
|
||||
|
||||
Otherwise, it is unspecified
|
||||
whether a deallocation function with a parameter of type std::size_t is selected[.](#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[.](#9.sentence-2)
|
||||
|
||||
[10](#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[.](#10.sentence-1)
|
||||
|
||||
[*Note [6](#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[.](#10.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
For an array delete expression,
|
||||
the deleted object is
|
||||
the array object[.](#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[.](#10.sentence-4)
|
||||
|
||||
[*Note [7](#note-7)*:
|
||||
|
||||
Any cv-qualifiers in the type of the deleted object
|
||||
are ignored when forming this argument[.](#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[.](#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[.](#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[.](#10.sentence-8)
|
||||
|
||||
[*Note [8](#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"))[.](#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*](expr.new#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)
|
||||
155
cppdraft/expr/dynamic/cast.md
Normal file
155
cppdraft/expr/dynamic/cast.md
Normal file
@@ -0,0 +1,155 @@
|
||||
[expr.dynamic.cast]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.dynamic.cast)
|
||||
|
||||
### 7.6.1 Postfix expressions [[expr.post]](expr.post#expr.dynamic.cast)
|
||||
|
||||
#### 7.6.1.7 Dynamic cast [expr.dynamic.cast]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4409)
|
||||
|
||||
The result of the expression dynamic_cast<T>(v) is the result of
|
||||
converting the expression v to type T[.](#1.sentence-1)
|
||||
|
||||
T shall be a pointer or reference to a complete class type, or
|
||||
âpointer to cv voidâ[.](#1.sentence-2)
|
||||
|
||||
The dynamic_cast operator shall not cast
|
||||
away constness ([[expr.const.cast]](expr.const.cast "7.6.1.11 Const cast"))[.](#1.sentence-3)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4419)
|
||||
|
||||
If T is a pointer type, v shall be a prvalue of a
|
||||
pointer to complete class type, and the result is a prvalue of typeT[.](#2.sentence-1)
|
||||
|
||||
If T is an lvalue reference type, v shall be
|
||||
an lvalue of a complete class type, and the result is an lvalue of the
|
||||
type referred to by T[.](#2.sentence-2)
|
||||
|
||||
If T is an rvalue reference type,v shall be a glvalue having a complete class type, and the
|
||||
result is an xvalue of the type referred to by T[.](#2.sentence-3)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4428)
|
||||
|
||||
If the type of v is the same as T (ignoring cv-qualifications),
|
||||
the result isv (converted if necessary)[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4433)
|
||||
|
||||
If T is âpointer to *cv1* Bâ and v has
|
||||
type âpointer to *cv2* Dâ such that B is a base
|
||||
class of D, the result is a pointer to the unique B subobject of the D object pointed to by v, or
|
||||
a null pointer value if v is a null pointer value[.](#4.sentence-1)
|
||||
|
||||
Similarly, ifT is âreference to *cv1* Bâ and v has
|
||||
type *cv2* D such that B is a base class ofD, the result is the unique B subobject of the D object referred to by v[.](#4.sentence-2)[51](#footnote-51 "The most derived object ([intro.object]) pointed or referred to by v can contain other B objects as base classes, but these are ignored.")
|
||||
|
||||
In both the pointer and
|
||||
reference cases, the program is ill-formed if B is an inaccessible or
|
||||
ambiguous base class of D[.](#4.sentence-3)
|
||||
|
||||
[*Example [1](#example-1)*: struct B { };struct D : B { };void foo(D* dp) { B* bp = dynamic_cast<B*>(dp); // equivalent to B* bp = dp;} â *end example*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4463)
|
||||
|
||||
Otherwise, v shall be a pointer to or a glvalue of a[polymorphic type](class.virtual#def:class,polymorphic "11.7.3 Virtual functions [class.virtual]")[.](#5.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4467)
|
||||
|
||||
If v is a null pointer value, the result is a null pointer value[.](#6.sentence-1)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4470)
|
||||
|
||||
If v has type âpointer to cv Uâ andv does not point to an object
|
||||
whose type is similar ([[conv.qual]](conv.qual "7.3.6 Qualification conversions")) to U and
|
||||
that is
|
||||
within its lifetime or
|
||||
within its period of construction or destruction ([[class.cdtor]](class.cdtor "11.9.5 Construction and destruction")),
|
||||
the behavior is undefined[.](#7.sentence-1)
|
||||
|
||||
If v is a glvalue of type U andv does not refer to an object
|
||||
whose type is similar to U and
|
||||
that is
|
||||
within its lifetime or
|
||||
within its period of construction or destruction,
|
||||
the behavior is undefined[.](#7.sentence-2)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4486)
|
||||
|
||||
If T is âpointer to cv voidâ, then the result
|
||||
is a pointer to the most derived object pointed to by v[.](#8.sentence-1)
|
||||
|
||||
Otherwise, a runtime check is applied to see if the object pointed or
|
||||
referred to by v can be converted to the type pointed or
|
||||
referred to by T[.](#8.sentence-2)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4493)
|
||||
|
||||
Let C be the class type to which T points or refers[.](#9.sentence-1)
|
||||
|
||||
The runtime
|
||||
check logically executes as follows:
|
||||
|
||||
- [(9.1)](#9.1)
|
||||
|
||||
If, in the most derived object pointed (referred) to by v,v points (refers) to a public base class subobject of aC object, and if only one object of type C is derived
|
||||
from the subobject pointed (referred) to by v,
|
||||
the result points (refers) to that C object[.](#9.1.sentence-1)
|
||||
|
||||
- [(9.2)](#9.2)
|
||||
|
||||
Otherwise, if v points (refers) to a public base
|
||||
class subobject of the most derived object, and the type of the most
|
||||
derived object has a base class, of type C, that is unambiguous
|
||||
and public, the result points (refers) to theC subobject of the most derived object[.](#9.2.sentence-1)
|
||||
|
||||
- [(9.3)](#9.3)
|
||||
|
||||
Otherwise, the
|
||||
runtime check [*fails*](#def:fails)[.](#9.3.sentence-1)
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4513)
|
||||
|
||||
The value of a failed cast to pointer type is the null pointer value of
|
||||
the required result type[.](#10.sentence-1)
|
||||
|
||||
A failed cast to reference type [throws
|
||||
an exception](except.throw "14.2 Throwing an exception [except.throw]") of a type that would match a[handler](except.handle "14.4 Handling an exception [except.handle]") of type [std::bad_cast](bad.cast "17.7.4 Class bad_cast [bad.cast]")[.](#10.sentence-2)
|
||||
|
||||
[*Example [2](#example-2)*: class A { virtual void f(); };class B { virtual void g(); };class D : public virtual A, private B { };void g() { D d;
|
||||
B* bp = (B*)&d; // cast needed to break protection A* ap = &d; // public derivation, no cast needed D& dr = dynamic_cast<D&>(*bp); // fails ap = dynamic_cast<A*>(bp); // fails bp = dynamic_cast<B*>(ap); // fails ap = dynamic_cast<A*>(&d); // succeeds bp = dynamic_cast<B*>(&d); // ill-formed (not a runtime check)}class E : public D, public B { };class F : public E, public D { };void h() { F f;
|
||||
A* ap = &f; // succeeds: finds unique A D* dp = dynamic_cast<D*>(ap); // fails: yields null; f has two D subobjects E* ep = (E*)ap; // error: cast from virtual base E* ep1 = dynamic_cast<E*>(ap); // succeeds} â *end example*]
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
Subclause [[class.cdtor]](class.cdtor "11.9.5 Construction and destruction") describes the behavior of a dynamic_cast applied to an object under construction or destruction[.](#10.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[51)](#footnote-51)[51)](#footnoteref-51)
|
||||
|
||||
The most derived
|
||||
object ([[intro.object]](intro.object "6.8.2 Object model")) pointed or referred to byv can contain other B objects as base classes, but these
|
||||
are ignored[.](#footnote-51.sentence-1)
|
||||
186
cppdraft/expr/eq.md
Normal file
186
cppdraft/expr/eq.md
Normal file
@@ -0,0 +1,186 @@
|
||||
[expr.eq]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.eq)
|
||||
|
||||
### 7.6.10 Equality operators [expr.eq]
|
||||
|
||||
[equality-expression:](#nt:equality-expression "7.6.10 Equality operators [expr.eq]")
|
||||
[*relational-expression*](expr.rel#nt:relational-expression "7.6.9 Relational operators [expr.rel]")
|
||||
[*equality-expression*](#nt:equality-expression "7.6.10 Equality operators [expr.eq]") == [*relational-expression*](expr.rel#nt:relational-expression "7.6.9 Relational operators [expr.rel]")
|
||||
[*equality-expression*](#nt:equality-expression "7.6.10 Equality operators [expr.eq]") != [*relational-expression*](expr.rel#nt:relational-expression "7.6.9 Relational operators [expr.rel]")
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7512)
|
||||
|
||||
The == (equal to) and the != (not equal to) operators
|
||||
group left-to-right[.](#1.sentence-1)
|
||||
|
||||
The
|
||||
lvalue-to-rvalue ([[conv.lval]](conv.lval "7.3.2 Lvalue-to-rvalue conversion"))
|
||||
and function-to-pointer ([[conv.func]](conv.func "7.3.4 Function-to-pointer conversion"))
|
||||
standard conversions are performed on the operands[.](#1.sentence-2)
|
||||
|
||||
If one of the operands is a pointer or a null pointer constant ([[conv.ptr]](conv.ptr "7.3.12 Pointer conversions")),
|
||||
the array-to-pointer conversion ([[conv.array]](conv.array "7.3.3 Array-to-pointer conversion")) is performed
|
||||
on the other operand[.](#1.sentence-3)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7523)
|
||||
|
||||
The converted operands shall have scalar type[.](#2.sentence-1)
|
||||
|
||||
The operators== and != both yield true or false, i.e., a
|
||||
result of type bool[.](#2.sentence-2)
|
||||
|
||||
In each case below, the operands shall have the
|
||||
same type after the specified conversions have been applied[.](#2.sentence-3)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7529)
|
||||
|
||||
If at least one of the converted operands is a pointer,[pointer conversions](conv.ptr "7.3.12 Pointer conversions [conv.ptr]"),[function pointer conversions](conv.fctptr "7.3.14 Function pointer conversions [conv.fctptr]"), and[qualification conversions](conv.qual "7.3.6 Qualification conversions [conv.qual]") are performed on both operands to bring them to their [composite pointer type](expr.type#def:composite_pointer_type "7.2.2 Type [expr.type]")[.](#3.sentence-1)
|
||||
|
||||
Comparing pointers is defined as follows:
|
||||
|
||||
- [(3.1)](#3.1)
|
||||
|
||||
If one pointer represents the address of a complete object, and another
|
||||
pointer represents the address one past the last element of a different
|
||||
complete object,[66](#footnote-66 "As specified in [basic.compound], an object that is not an array element is considered to belong to a single-element array for this purpose.") the result of the comparison is unspecified[.](#3.1.sentence-1)
|
||||
|
||||
- [(3.2)](#3.2)
|
||||
|
||||
Otherwise, if the pointers are both null, both point to the samefunction, or both[represent the same address](basic.compound#def:represents_the_address "6.9.4 Compound types [basic.compound]"),
|
||||
they compare equal[.](#3.2.sentence-1)
|
||||
|
||||
- [(3.3)](#3.3)
|
||||
|
||||
Otherwise, the pointers compare unequal[.](#3.3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7559)
|
||||
|
||||
If at least one of the operands is a pointer to member,
|
||||
pointer-to-member conversions ([[conv.mem]](conv.mem "7.3.13 Pointer-to-member conversions")),
|
||||
function pointer conversions ([[conv.fctptr]](conv.fctptr "7.3.14 Function pointer conversions")), and
|
||||
qualification conversions ([[conv.qual]](conv.qual "7.3.6 Qualification conversions"))
|
||||
are performed on both operands to bring them to
|
||||
their composite pointer type ([[expr.type]](expr.type "7.2.2 Type"))[.](#4.sentence-1)
|
||||
|
||||
Comparing pointers to members is defined as follows:
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
If two pointers to members are both the null member pointer value, they compare
|
||||
equal[.](#4.1.sentence-1)
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
If only one of two pointers to members is the null member pointer value, they
|
||||
compare unequal[.](#4.2.sentence-1)
|
||||
|
||||
- [(4.3)](#4.3)
|
||||
|
||||
If either is a pointer to a virtual member function, the result is unspecified[.](#4.3.sentence-1)
|
||||
|
||||
- [(4.4)](#4.4)
|
||||
|
||||
If one refers to a member of class C1 and the other refers to a member
|
||||
of a different class C2, where neither is a base class of the other,
|
||||
the result is unspecified[.](#4.4.sentence-1)
|
||||
[*Example [1](#example-1)*: struct A {};struct B : A { int x; };struct C : A { int x; };
|
||||
|
||||
int A::*bx = (int(A::*))&B::x;int A::*cx = (int(A::*))&C::x;
|
||||
|
||||
bool b1 = (bx == cx); // unspecified â *end example*]
|
||||
|
||||
- [(4.5)](#4.5)
|
||||
|
||||
If both refer to (possibly different) members of the same [union](class.union "11.5 Unions [class.union]"),
|
||||
they compare equal[.](#4.5.sentence-1)
|
||||
|
||||
- [(4.6)](#4.6)
|
||||
|
||||
Otherwise, two pointers to members compare equal if they would refer to the same member of
|
||||
the same [most derived object](intro.object#def:most_derived_object "6.8.2 Object model [intro.object]") or the same subobject if
|
||||
indirection with a hypothetical object of the associated
|
||||
class type were performed, otherwise they compare unequal[.](#4.6.sentence-1)
|
||||
[*Example [2](#example-2)*: struct B {int f();};struct L : B { };struct R : B { };struct D : L, R { };
|
||||
|
||||
int (B::*pb)() = &B::f;int (L::*pl)() = pb;int (R::*pr)() = pb;int (D::*pdl)() = pl;int (D::*pdr)() = pr;bool x = (pdl == pdr); // falsebool y = (pb == pl); // true â *end example*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7625)
|
||||
|
||||
Two operands of type std::nullptr_t or one operand of typestd::nullptr_t and the other a null pointer constant compare equal[.](#5.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7629)
|
||||
|
||||
If both operands are of type std::meta::info,
|
||||
they compare equal if both operands
|
||||
|
||||
- [(6.1)](#6.1)
|
||||
|
||||
are null reflection values,
|
||||
|
||||
- [(6.2)](#6.2)
|
||||
|
||||
represent values that are template-argument-equivalent ([[temp.type]](temp.type "13.6 Type equivalence")),
|
||||
|
||||
- [(6.3)](#6.3)
|
||||
|
||||
represent the same object,
|
||||
|
||||
- [(6.4)](#6.4)
|
||||
|
||||
represent the same entity,
|
||||
|
||||
- [(6.5)](#6.5)
|
||||
|
||||
represent the same annotation ([[dcl.attr.annotation]](dcl.attr.annotation "9.13.12 Annotations")),
|
||||
|
||||
- [(6.6)](#6.6)
|
||||
|
||||
represent the same direct base class relationship, or
|
||||
|
||||
- [(6.7)](#6.7)
|
||||
|
||||
represent equal data member descriptions ([[class.mem.general]](class.mem.general "11.4.1 General")),
|
||||
|
||||
and they compare unequal otherwise[.](#6.sentence-1)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7643)
|
||||
|
||||
If two operands compare equal, the result is true for
|
||||
the == operator and false for the != operator[.](#7.sentence-1)
|
||||
|
||||
If two operands
|
||||
compare unequal, the result is false for the == operator andtrue for the != operator[.](#7.sentence-2)
|
||||
|
||||
Otherwise, the result of each of the
|
||||
operators is unspecified[.](#7.sentence-3)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7650)
|
||||
|
||||
If both operands are of arithmetic or enumeration type, the usual arithmetic
|
||||
conversions ([[expr.arith.conv]](expr.arith.conv "7.4 Usual arithmetic conversions")) are performed on both operands; each of the operators shall yieldtrue if the specified relationship is true and false if it is
|
||||
false[.](#8.sentence-1)
|
||||
|
||||
[66)](#footnote-66)[66)](#footnoteref-66)
|
||||
|
||||
As specified in [[basic.compound]](basic.compound "6.9.4 Compound types"),
|
||||
an object that is not an array element is
|
||||
considered to belong to a single-element array for this purpose[.](#footnote-66.sentence-1)
|
||||
37
cppdraft/expr/log/and.md
Normal file
37
cppdraft/expr/log/and.md
Normal file
@@ -0,0 +1,37 @@
|
||||
[expr.log.and]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.log.and)
|
||||
|
||||
### 7.6.14 Logical AND operator [expr.log.and]
|
||||
|
||||
[logical-and-expression:](#nt:logical-and-expression "7.6.14 Logical AND operator [expr.log.and]")
|
||||
[*inclusive-or-expression*](expr.or#nt:inclusive-or-expression "7.6.13 Bitwise inclusive OR operator [expr.or]")
|
||||
[*logical-and-expression*](#nt:logical-and-expression "7.6.14 Logical AND operator [expr.log.and]") && [*inclusive-or-expression*](expr.or#nt:inclusive-or-expression "7.6.13 Bitwise inclusive OR operator [expr.or]")
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7744)
|
||||
|
||||
The && operator groups left-to-right[.](#1.sentence-1)
|
||||
|
||||
The operands are both
|
||||
contextually converted to bool ([[conv]](conv "7.3 Standard conversions"))[.](#1.sentence-2)
|
||||
|
||||
The
|
||||
result is true if both operands are true andfalse otherwise[.](#1.sentence-3)
|
||||
|
||||
Unlike &, && guarantees
|
||||
left-to-right evaluation: the second operand is not evaluated if the
|
||||
first operand is false[.](#1.sentence-4)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7753)
|
||||
|
||||
The result is a bool[.](#2.sentence-1)
|
||||
|
||||
If the second expression is evaluated,
|
||||
the first expression is sequenced before
|
||||
the second expression ([[intro.execution]](intro.execution "6.10.1 Sequential execution"))[.](#2.sentence-2)
|
||||
36
cppdraft/expr/log/or.md
Normal file
36
cppdraft/expr/log/or.md
Normal file
@@ -0,0 +1,36 @@
|
||||
[expr.log.or]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.log.or)
|
||||
|
||||
### 7.6.15 Logical OR operator [expr.log.or]
|
||||
|
||||
[logical-or-expression:](#nt:logical-or-expression "7.6.15 Logical OR operator [expr.log.or]")
|
||||
[*logical-and-expression*](expr.log.and#nt:logical-and-expression "7.6.14 Logical AND operator [expr.log.and]")
|
||||
[*logical-or-expression*](#nt:logical-or-expression "7.6.15 Logical OR operator [expr.log.or]") || [*logical-and-expression*](expr.log.and#nt:logical-and-expression "7.6.14 Logical AND operator [expr.log.and]")
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7771)
|
||||
|
||||
The || operator groups left-to-right[.](#1.sentence-1)
|
||||
|
||||
The operands are both
|
||||
contextually converted to bool ([[conv]](conv "7.3 Standard conversions"))[.](#1.sentence-2)
|
||||
|
||||
The result istrue if either of its operands is true, andfalse otherwise[.](#1.sentence-3)
|
||||
|
||||
Unlike |, || guarantees
|
||||
left-to-right evaluation; moreover, the second operand is not evaluated
|
||||
if the first operand evaluates to true[.](#1.sentence-4)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7780)
|
||||
|
||||
The result is a bool[.](#2.sentence-1)
|
||||
|
||||
If the second expression is evaluated,
|
||||
the first expression is sequenced before
|
||||
the second expression ([[intro.execution]](intro.execution "6.10.1 Sequential execution"))[.](#2.sentence-2)
|
||||
111
cppdraft/expr/mptr/oper.md
Normal file
111
cppdraft/expr/mptr/oper.md
Normal file
@@ -0,0 +1,111 @@
|
||||
[expr.mptr.oper]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.mptr.oper)
|
||||
|
||||
### 7.6.4 Pointer-to-member operators [expr.mptr.oper]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6956)
|
||||
|
||||
The pointer-to-member operators ->* and .* group
|
||||
left-to-right[.](#1.sentence-1)
|
||||
|
||||
[pm-expression:](#nt:pm-expression "7.6.4 Pointer-to-member operators [expr.mptr.oper]")
|
||||
[*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]")
|
||||
[*pm-expression*](#nt:pm-expression "7.6.4 Pointer-to-member operators [expr.mptr.oper]") .* [*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]")
|
||||
[*pm-expression*](#nt:pm-expression "7.6.4 Pointer-to-member operators [expr.mptr.oper]") ->* [*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]")
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6973)
|
||||
|
||||
The binary operator .* binds its second operand, which shall be
|
||||
a prvalue
|
||||
of type âpointer to member of Tâ to its first operand, which shall be
|
||||
a glvalue
|
||||
of
|
||||
class T or of a class of which T is an unambiguous and
|
||||
accessible base class[.](#2.sentence-1)
|
||||
|
||||
The result is an object or a function of the type
|
||||
specified by the second operand[.](#2.sentence-2)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6983)
|
||||
|
||||
The binary operator ->* binds its second operand, which shall be
|
||||
a prvalue
|
||||
of type âpointer to member of Tâ to its first operand, which shall be of
|
||||
type âpointer to Uâ
|
||||
where U is either T or
|
||||
a class of which T is an unambiguous and accessible base class[.](#3.sentence-1)
|
||||
|
||||
The expression E1->*E2 is converted into the equivalent form(*(E1)).*E2[.](#3.sentence-2)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6994)
|
||||
|
||||
Abbreviating [*pm-expression*](#nt:pm-expression "7.6.4 Pointer-to-member operators [expr.mptr.oper]").*[*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]") as E1.*E2, E1 is called the [*object expression*](#def:object_expression "7.6.4 Pointer-to-member operators [expr.mptr.oper]")[.](#4.sentence-1)
|
||||
|
||||
If the result of E1 is an object
|
||||
whose type is not similar to the type of E1, or
|
||||
whose most derived object does not
|
||||
contain the member to whichE2 refers, the behavior is undefined[.](#4.sentence-2)
|
||||
|
||||
The expression E1 is sequenced before the expression E2[.](#4.sentence-3)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7004)
|
||||
|
||||
The restrictions on cv-qualification, and the manner in which
|
||||
the cv-qualifiers of the operands are combined to produce the
|
||||
cv-qualifiers of the result, are the same as the rules forE1.E2 given in [[expr.ref]](expr.ref "7.6.1.5 Class member access")[.](#5.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
It is not possible to use a pointer to member that refers to amutable member to modify a const class object[.](#5.sentence-2)
|
||||
|
||||
For
|
||||
example,struct S { S() : i(0) { }mutable int i;};void f(){const S cs; int S::* pm = &S::i; // pm refers to mutable member S::i cs.*pm = 88; // error: cs is a const object}
|
||||
|
||||
â *end note*]
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7027)
|
||||
|
||||
If the result of .* or ->* is a function, then that
|
||||
result can be used only as the operand for the function call operator()[.](#6.sentence-1)
|
||||
|
||||
[*Example [1](#example-1)*:
|
||||
|
||||
(ptr_to_obj->*ptr_to_mfct)(10); calls the member function denoted by ptr_to_mfct for the object
|
||||
pointed to by ptr_to_obj[.](#6.sentence-2)
|
||||
|
||||
â *end example*]
|
||||
|
||||
In a .* expression whose object expression is an rvalue, the program is
|
||||
ill-formed if the second operand is a pointer to member function
|
||||
whose [*ref-qualifier*](dcl.decl.general#nt:ref-qualifier "9.3.1 General [dcl.decl.general]") is &,
|
||||
unless its [*cv-qualifier-seq*](dcl.decl.general#nt:cv-qualifier-seq "9.3.1 General [dcl.decl.general]") is const[.](#6.sentence-3)
|
||||
|
||||
In a .* expression whose object expression is an lvalue, the program is ill-formed if the second
|
||||
operand is
|
||||
a pointer to member function
|
||||
whose [*ref-qualifier*](dcl.decl.general#nt:ref-qualifier "9.3.1 General [dcl.decl.general]") is &&[.](#6.sentence-4)
|
||||
|
||||
The result of a .* expression
|
||||
whose second operand is a pointer to a data member is an lvalue if the first
|
||||
operand is an lvalue and an xvalue otherwise[.](#6.sentence-5)
|
||||
|
||||
The result of a .* expression whose
|
||||
second operand is a pointer to a member function is a prvalue[.](#6.sentence-6)
|
||||
|
||||
If the second operand is the [null member pointer value](conv.mem#def:value,null_member_pointer "7.3.13 Pointer-to-member conversions [conv.mem]"),
|
||||
the behavior is undefined[.](#6.sentence-7)
|
||||
55
cppdraft/expr/mul.md
Normal file
55
cppdraft/expr/mul.md
Normal file
@@ -0,0 +1,55 @@
|
||||
[expr.mul]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.mul)
|
||||
|
||||
### 7.6.5 Multiplicative operators [expr.mul]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7059)
|
||||
|
||||
The multiplicative operators *, /, and % group
|
||||
left-to-right[.](#1.sentence-1)
|
||||
|
||||
[multiplicative-expression:](#nt:multiplicative-expression "7.6.5 Multiplicative operators [expr.mul]")
|
||||
[*pm-expression*](expr.mptr.oper#nt:pm-expression "7.6.4 Pointer-to-member operators [expr.mptr.oper]")
|
||||
[*multiplicative-expression*](#nt:multiplicative-expression "7.6.5 Multiplicative operators [expr.mul]") * [*pm-expression*](expr.mptr.oper#nt:pm-expression "7.6.4 Pointer-to-member operators [expr.mptr.oper]")
|
||||
[*multiplicative-expression*](#nt:multiplicative-expression "7.6.5 Multiplicative operators [expr.mul]") / [*pm-expression*](expr.mptr.oper#nt:pm-expression "7.6.4 Pointer-to-member operators [expr.mptr.oper]")
|
||||
[*multiplicative-expression*](#nt:multiplicative-expression "7.6.5 Multiplicative operators [expr.mul]") % [*pm-expression*](expr.mptr.oper#nt:pm-expression "7.6.4 Pointer-to-member operators [expr.mptr.oper]")
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7079)
|
||||
|
||||
The operands of * and / shall have arithmetic or unscoped
|
||||
enumeration type; the operands of % shall have integral or unscoped
|
||||
enumeration type[.](#2.sentence-1)
|
||||
|
||||
The [usual arithmetic conversions](expr.arith.conv "7.4 Usual arithmetic conversions [expr.arith.conv]") are performed on the
|
||||
operands and determine the type of the result[.](#2.sentence-2)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7085)
|
||||
|
||||
The binary * operator indicates multiplication[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7088)
|
||||
|
||||
The binary / operator yields the quotient, and the binary% operator yields the remainder from the division of the first
|
||||
expression by the second[.](#4.sentence-1)
|
||||
|
||||
If the second operand of / or % is zero, the behavior is
|
||||
undefined[.](#4.sentence-2)
|
||||
|
||||
For integral operands, the / operator yields the algebraic quotient with
|
||||
any fractional part discarded;[63](#footnote-63 "This is often called truncation towards zero.") if the quotient a/b is representable in the type of the result,(a/b)*b + a%b is equal to a; otherwise, the behavior
|
||||
of both a/b and a%b is undefined[.](#4.sentence-3)
|
||||
|
||||
[63)](#footnote-63)[63)](#footnoteref-63)
|
||||
|
||||
This is often called truncation towards zero[.](#footnote-63.sentence-1)
|
||||
667
cppdraft/expr/new.md
Normal file
667
cppdraft/expr/new.md
Normal file
@@ -0,0 +1,667 @@
|
||||
[expr.new]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.new)
|
||||
|
||||
### 7.6.2 Unary expressions [[expr.unary]](expr.unary#expr.new)
|
||||
|
||||
#### 7.6.2.8 New [expr.new]
|
||||
|
||||
[1](#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[.](#1.sentence-1)
|
||||
|
||||
The type of that object is the [*allocated type*](#def:type,allocated "7.6.2.8 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"))[.](#1.sentence-3)
|
||||
|
||||
[*Note [1](#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*[.](#1.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Note [2](#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[.](#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](#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](#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](#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*[.](#3.sentence-1)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
This prevents ambiguities between the declarator operators &, &&,*, and [] and their expression counterparts[.](#3.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [2](#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[.](#3.sentence-3)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5856)
|
||||
|
||||
[*Note [4](#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[.](#4.sentence-1)
|
||||
|
||||
[*Example [3](#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)[.](#4.sentence-4)
|
||||
|
||||
â *end example*]
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#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[.](#5.sentence-1)
|
||||
|
||||
[6](#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[.](#6.sentence-1)
|
||||
|
||||
[*Example [4](#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)[.](#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)[.](#6.sentence-3)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[7](#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"))[.](#7.sentence-1)
|
||||
|
||||
[8](#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[.](#8.sentence-1)
|
||||
|
||||
The value of the [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") is invalid if
|
||||
|
||||
- [(8.1)](#8.1)
|
||||
|
||||
the expression is of non-class type and its value before converting tostd::size_t is less than zero;
|
||||
|
||||
- [(8.2)](#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)](#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)](#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[.](#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)](#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)](#8.6)
|
||||
|
||||
otherwise, an allocation function is not called; instead
|
||||
* [(8.6.1)](#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)](#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]")[.](#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[.](#8.sentence-4)
|
||||
|
||||
[9](#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"))[.](#9.sentence-1)
|
||||
|
||||
[*Note [5](#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[.](#9.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[10](#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"))[.](#10.sentence-1)
|
||||
|
||||
[*Note [6](#note-6)*:
|
||||
|
||||
The lifetime of such an object is not necessarily restricted to the
|
||||
scope in which it is created[.](#10.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[11](#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[.](#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[.](#11.sentence-2)
|
||||
|
||||
[*Note [7](#note-7)*:
|
||||
|
||||
Both new int and new int[10] have type int* and
|
||||
the type of new int[i][10] is int (*)[10][.](#11.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[12](#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"))[.](#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]")[.](#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[.](#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[][.](#12.sentence-4)
|
||||
|
||||
[*Note [8](#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"))[.](#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"))[.](#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")[.](#12.sentence-7)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[13](#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"))[.](#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[.](#13.sentence-2)
|
||||
|
||||
[14](#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"))[.](#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]")[.](#14.sentence-2)
|
||||
|
||||
[15](#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"))[.](#15.sentence-1)
|
||||
|
||||
[16](#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)](#16.1)
|
||||
|
||||
the evaluation of e1 is sequenced before the evaluation ofe2, and
|
||||
|
||||
- [(16.2)](#16.2)
|
||||
|
||||
e2 is evaluated whenever e1 obtains storage, and
|
||||
|
||||
- [(16.3)](#16.3)
|
||||
|
||||
both e1 and e2 invoke the same replaceable global
|
||||
allocation function, and
|
||||
|
||||
- [(16.4)](#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)](#16.5)
|
||||
|
||||
the pointer values produced by e1 and e2 are operands to
|
||||
evaluated [*delete-expression*](expr.delete#nt:delete-expression "7.6.2.9 Delete [expr.delete]")*s*, and
|
||||
|
||||
- [(16.6)](#16.6)
|
||||
|
||||
the evaluation of e2 is sequenced before the evaluation of the[*delete-expression*](expr.delete#nt:delete-expression "7.6.2.9 Delete [expr.delete]") whose operand is the pointer value produced
|
||||
by e1[.](#16.sentence-1)
|
||||
|
||||
[*Example [5](#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](#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[.](#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"))[.](#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[.](#17.sentence-3)
|
||||
|
||||
[*Note [9](#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[.](#17.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[18](#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[.](#18.sentence-1)
|
||||
|
||||
[19](#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]")*[.](#19.sentence-1)
|
||||
|
||||
[20](#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[.](#20.sentence-1)
|
||||
|
||||
The first argument is
|
||||
the amount of space requested,
|
||||
and has type std::size_t[.](#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[.](#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[.](#20.sentence-4)
|
||||
|
||||
If no matching function is found then
|
||||
|
||||
- [(20.1)](#20.1)
|
||||
|
||||
if the allocated object type has new-extended alignment,
|
||||
the alignment argument is removed from the argument list;
|
||||
|
||||
- [(20.2)](#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[.](#20.sentence-5)
|
||||
|
||||
[21](#21)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6181)
|
||||
|
||||
[*Example [6](#example-6)*:
|
||||
|
||||
- [(21.1)](#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)](#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)](#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)](#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*)[.](#21.sentence-1)
|
||||
|
||||
The amount of overhead may vary from one
|
||||
invocation of new to another[.](#21.sentence-2)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[22](#22)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6216)
|
||||
|
||||
[*Note [10](#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[.](#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[.](#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[.](#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[.](#22.sentence-4)
|
||||
|
||||
[23](#23)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L6238)
|
||||
|
||||
[*Note [11](#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[.](#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[.](#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[.](#23.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[24](#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)](#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"))[.](#24.1.sentence-1)
|
||||
[*Note [12](#note-12)*:
|
||||
If no initialization
|
||||
is performed, the object has an indeterminate value[.](#24.1.sentence-2)
|
||||
â *end note*]
|
||||
|
||||
- [(24.2)](#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[.](#24.2.sentence-1)
|
||||
|
||||
[25](#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]")[.](#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]")[.](#25.sentence-2)
|
||||
|
||||
[26](#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"))[.](#26.sentence-1)
|
||||
|
||||
[27](#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]")[.](#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[.](#27.sentence-2)
|
||||
|
||||
[*Note [13](#note-13)*:
|
||||
|
||||
This is appropriate when the called allocation function does not
|
||||
allocate memory; otherwise, it is likely to result in a memory leak[.](#27.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[28](#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[.](#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[.](#28.sentence-2)
|
||||
|
||||
[29](#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[.](#29.sentence-1)
|
||||
|
||||
If
|
||||
the lookup finds a single matching deallocation function, that function
|
||||
will be called; otherwise, no deallocation function will be called[.](#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[.](#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"))[.](#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[.](#29.sentence-5)
|
||||
|
||||
[*Example [7](#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](#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*[.](#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[.](#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[.](#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)
|
||||
31
cppdraft/expr/or.md
Normal file
31
cppdraft/expr/or.md
Normal file
@@ -0,0 +1,31 @@
|
||||
[expr.or]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.or)
|
||||
|
||||
### 7.6.13 Bitwise inclusive OR operator [expr.or]
|
||||
|
||||
[inclusive-or-expression:](#nt:inclusive-or-expression "7.6.13 Bitwise inclusive OR operator [expr.or]")
|
||||
[*exclusive-or-expression*](expr.xor#nt:exclusive-or-expression "7.6.12 Bitwise exclusive OR operator [expr.xor]")
|
||||
[*inclusive-or-expression*](#nt:inclusive-or-expression "7.6.13 Bitwise inclusive OR operator [expr.or]") | [*exclusive-or-expression*](expr.xor#nt:exclusive-or-expression "7.6.12 Bitwise exclusive OR operator [expr.xor]")
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7719)
|
||||
|
||||
The | operator groups left-to-right[.](#1.sentence-1)
|
||||
|
||||
The operands shall be of integral or unscoped enumeration type[.](#1.sentence-2)
|
||||
|
||||
The usual arithmetic conversions ([[expr.arith.conv]](expr.arith.conv "7.4 Usual arithmetic conversions")) are performed[.](#1.sentence-3)
|
||||
|
||||
Given the coefficients xi and yi of the base-2 representation ([[basic.fundamental]](basic.fundamental "6.9.2 Fundamental types"))
|
||||
of the converted operands x and y,
|
||||
the coefficient ri of the base-2 representation of the result r is 1 if at least one of xi and yi is 1, and 0 otherwise[.](#1.sentence-4)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
The result is the bitwise inclusive or function of the operands[.](#1.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
1710
cppdraft/expr/post.md
Normal file
1710
cppdraft/expr/post.md
Normal file
File diff suppressed because it is too large
Load Diff
49
cppdraft/expr/post/general.md
Normal file
49
cppdraft/expr/post/general.md
Normal file
@@ -0,0 +1,49 @@
|
||||
[expr.post.general]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.post.general)
|
||||
|
||||
### 7.6.1 Postfix expressions [[expr.post]](expr.post#general)
|
||||
|
||||
#### 7.6.1.1 General [expr.post.general]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3658)
|
||||
|
||||
Postfix expressions group left-to-right[.](#1.sentence-1)
|
||||
|
||||
[postfix-expression:](#nt:postfix-expression "7.6.1.1 General [expr.post.general]")
|
||||
[*primary-expression*](expr.prim.grammar#nt:primary-expression "7.5.1 Grammar [expr.prim.grammar]")
|
||||
[*postfix-expression*](#nt:postfix-expression "7.6.1.1 General [expr.post.general]") [ [*expression-list*](#nt:expression-list "7.6.1.1 General [expr.post.general]")opt ]
|
||||
[*postfix-expression*](#nt:postfix-expression "7.6.1.1 General [expr.post.general]") ( [*expression-list*](#nt:expression-list "7.6.1.1 General [expr.post.general]")opt )
|
||||
[*simple-type-specifier*](dcl.type.simple#nt:simple-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") ( [*expression-list*](#nt:expression-list "7.6.1.1 General [expr.post.general]")opt )
|
||||
[*typename-specifier*](temp.res.general#nt:typename-specifier "13.8.1 General [temp.res.general]") ( [*expression-list*](#nt:expression-list "7.6.1.1 General [expr.post.general]")opt )
|
||||
[*simple-type-specifier*](dcl.type.simple#nt:simple-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]")
|
||||
[*typename-specifier*](temp.res.general#nt:typename-specifier "13.8.1 General [temp.res.general]") [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]")
|
||||
[*postfix-expression*](#nt:postfix-expression "7.6.1.1 General [expr.post.general]") . templateopt [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]")
|
||||
[*postfix-expression*](#nt:postfix-expression "7.6.1.1 General [expr.post.general]") . [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]")
|
||||
[*postfix-expression*](#nt:postfix-expression "7.6.1.1 General [expr.post.general]") -> templateopt [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]")
|
||||
[*postfix-expression*](#nt:postfix-expression "7.6.1.1 General [expr.post.general]") -> [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]")
|
||||
[*postfix-expression*](#nt:postfix-expression "7.6.1.1 General [expr.post.general]") ++
|
||||
[*postfix-expression*](#nt:postfix-expression "7.6.1.1 General [expr.post.general]") --
|
||||
dynamic_cast < [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") > ( [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") )
|
||||
static_cast < [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") > ( [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") )
|
||||
reinterpret_cast < [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") > ( [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") )
|
||||
const_cast < [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") > ( [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") )
|
||||
typeid ( [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") )
|
||||
typeid ( [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") )
|
||||
|
||||
[expression-list:](#nt:expression-list "7.6.1.1 General [expr.post.general]")
|
||||
[*initializer-list*](dcl.init.general#nt:initializer-list "9.5.1 General [dcl.init.general]")
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3689)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
The > token following the[*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") in a dynamic_cast,static_cast, reinterpret_cast, orconst_cast can be the product of replacing a>> token by two consecutive > tokens ([[temp.names]](temp.names "13.3 Names of template specializations"))[.](#2.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
67
cppdraft/expr/post/incr.md
Normal file
67
cppdraft/expr/post/incr.md
Normal file
@@ -0,0 +1,67 @@
|
||||
[expr.post.incr]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.post.incr)
|
||||
|
||||
### 7.6.1 Postfix expressions [[expr.post]](expr.post#incr)
|
||||
|
||||
#### 7.6.1.6 Increment and decrement [expr.post.incr]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4364)
|
||||
|
||||
The value of a postfix ++ expression is the value obtained by
|
||||
applying the lvalue-to-rvalue conversion ([[conv.lval]](conv.lval "7.3.2 Lvalue-to-rvalue conversion")) to its operand[.](#1.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
The value obtained is a copy of the original value[.](#1.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
The operand shall be a modifiable lvalue[.](#1.sentence-3)
|
||||
|
||||
The type of the operand shall
|
||||
be an arithmetic type other than cv bool,
|
||||
or a pointer to a complete object type[.](#1.sentence-4)
|
||||
|
||||
An operand with volatile-qualified type is deprecated;
|
||||
see [[depr.volatile.type]](depr.volatile.type "D.4 Deprecated volatile types")[.](#1.sentence-5)
|
||||
|
||||
The value of the operand object is modified ([[defns.access]](defns.access "3.1 access"))
|
||||
as if it were the operand of the prefix ++ operator ([[expr.pre.incr]](expr.pre.incr "7.6.2.3 Increment and decrement"))[.](#1.sentence-6)
|
||||
|
||||
Thevalue computation of the ++ expression is sequenced before the
|
||||
modification of the operand object[.](#1.sentence-7)
|
||||
|
||||
With respect to an
|
||||
indeterminately-sequenced function call, the operation of postfix++ is
|
||||
a single evaluation[.](#1.sentence-8)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
Therefore, a function call cannot intervene between the
|
||||
lvalue-to-rvalue conversion and the side effect associated with any
|
||||
single postfix ++ operator[.](#1.sentence-9)
|
||||
|
||||
â *end note*]
|
||||
|
||||
The result is a prvalue[.](#1.sentence-10)
|
||||
|
||||
The type of the result is the cv-unqualified
|
||||
version of the type of the operand[.](#1.sentence-11)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4396)
|
||||
|
||||
The operand of postfix -- is decremented analogously to the
|
||||
postfix ++ operator[.](#2.sentence-1)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
For prefix increment and decrement, see [[expr.pre.incr]](expr.pre.incr "7.6.2.3 Increment and decrement")[.](#2.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
139
cppdraft/expr/pre.md
Normal file
139
cppdraft/expr/pre.md
Normal file
@@ -0,0 +1,139 @@
|
||||
[expr.pre]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.1 Preamble [expr.pre]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L18)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
[[expr]](expr "7 Expressions") defines the syntax, order of evaluation, and meaning
|
||||
of expressions[.](#1.sentence-1)[39](#footnote-39 "The precedence of operators is not directly specified, but it can be derived from the syntax.")
|
||||
|
||||
An expression is a sequence of operators and operands that specifies a
|
||||
computation[.](#1.sentence-2)
|
||||
|
||||
An expression can result in a value and can cause side
|
||||
effects[.](#1.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L32)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
Operators can be overloaded, that is, given meaning when applied to
|
||||
expressions of <class> type or[enumeration](dcl.enum "9.8.1 Enumeration declarations [dcl.enum]") type[.](#2.sentence-1)
|
||||
|
||||
Uses of overloaded operators are transformed into
|
||||
function calls as described in [[over.oper]](over.oper "12.4 Overloaded operators")[.](#2.sentence-2)
|
||||
|
||||
Overloaded operators
|
||||
obey the rules for syntax and evaluation order specified in [[expr.compound]](expr.compound "7.6 Compound expressions"),
|
||||
but the requirements of operand type and value category are replaced
|
||||
by the rules for function call[.](#2.sentence-3)
|
||||
|
||||
Relations between operators, such as++a meaning a += 1, are not guaranteed for [overloaded
|
||||
operators](over.oper "12.4 Overloaded operators [over.oper]")[.](#2.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L46)
|
||||
|
||||
Subclause [[expr.compound]](expr.compound "7.6 Compound expressions") defines the effects of operators when applied to types
|
||||
for which they have not been overloaded[.](#3.sentence-1)
|
||||
|
||||
Operator overloading shall not
|
||||
modify the rules for the [*built-in operators*](#def:operators,built-in "7.1 Preamble [expr.pre]"),
|
||||
that is, for operators applied to types for which they are defined by this
|
||||
Standard[.](#3.sentence-2)
|
||||
|
||||
However, these built-in operators participate in overload
|
||||
resolution, and as part of that process user-defined conversions will be
|
||||
considered where necessary to convert the operands to types appropriate
|
||||
for the built-in operator[.](#3.sentence-3)
|
||||
|
||||
If a built-in operator is selected, such
|
||||
conversions will be applied to the operands before the operation is
|
||||
considered further according to the rules in [[expr.compound]](expr.compound "7.6 Compound expressions");
|
||||
see [[over.match.oper]](over.match.oper "12.2.2.3 Operators in expressions"), [[over.built]](over.built "12.5 Built-in operators")[.](#3.sentence-4)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L59)
|
||||
|
||||
If during the evaluation of an expression, the result is not
|
||||
mathematically defined or not in the range of representable values for
|
||||
its type, the behavior is undefined[.](#4.sentence-1)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
Treatment of division by zero, forming a remainder using a zero divisor,
|
||||
and all floating-point exceptions varies among machines, and is sometimes
|
||||
adjustable by a library function[.](#4.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L75)
|
||||
|
||||
[*Note [4](#note-4)*:
|
||||
|
||||
The implementation can regroup operators according to
|
||||
the usual mathematical rules only
|
||||
where the operators really are associative or commutative[.](#5.sentence-1)[40](#footnote-40 "Overloaded operators are never assumed to be associative or commutative.")
|
||||
|
||||
For example, in the following fragmentint a, b;/* ... */ a = a + 32760 + b + 5; the expression statement behaves exactly the same asa = (((a + 32760) + b) + 5); due to the associativity and precedence of these operators[.](#5.sentence-2)
|
||||
|
||||
Thus, the
|
||||
result of the sum (a + 32760) is next added to b, and
|
||||
that result is then added to 5 which results in the value assigned toa[.](#5.sentence-3)
|
||||
|
||||
On a machine in which overflows produce an exception and in
|
||||
which the range of values representable by an int is
|
||||
[-32768, +32767], the implementation cannot rewrite this
|
||||
expression asa = ((a + b) + 32765); since if the values for a and b were, respectively,â32754 and â15, the sum a + b would produce an exception while
|
||||
the original expression would not; nor can the expression be rewritten
|
||||
as eithera = ((a + 32765) + b); ora = (a + (b + 32765)); since the values for a and b might have been,
|
||||
respectively, 4 and â8 or â17 and 12[.](#5.sentence-4)
|
||||
|
||||
However on a machine in which
|
||||
overflows do not produce an exception and in which the results of
|
||||
overflows are reversible, the above expression statement can be
|
||||
rewritten by the implementation in any of the above ways because the
|
||||
same result will occur[.](#5.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L125)
|
||||
|
||||
The values of the floating-point operands and
|
||||
the results of floating-point expressions
|
||||
may be represented in greater precision and range than that
|
||||
required by the type; the types are not changed
|
||||
thereby[.](#6.sentence-1)[41](#footnote-41 "The cast and assignment operators must still perform their specific conversions as described in [expr.type.conv], [expr.cast], [expr.static.cast] and [expr.assign].")
|
||||
|
||||
[39)](#footnote-39)[39)](#footnoteref-39)
|
||||
|
||||
The precedence of operators is not directly specified, but it can be
|
||||
derived from the syntax[.](#footnote-39.sentence-1)
|
||||
|
||||
[40)](#footnote-40)[40)](#footnoteref-40)
|
||||
|
||||
Overloaded
|
||||
operators are never assumed to be associative or commutative[.](#footnote-40.sentence-1)
|
||||
|
||||
[41)](#footnote-41)[41)](#footnoteref-41)
|
||||
|
||||
The cast and assignment operators must still perform their specific
|
||||
conversions as described in [[expr.type.conv]](expr.type.conv "7.6.1.4 Explicit type conversion (functional notation)"), [[expr.cast]](expr.cast "7.6.3 Explicit type conversion (cast notation)"),[[expr.static.cast]](expr.static.cast "7.6.1.9 Static cast") and [[expr.assign]](expr.assign "7.6.19 Assignment and compound assignment operators")[.](#footnote-41.sentence-1)
|
||||
27
cppdraft/expr/pre/incr.md
Normal file
27
cppdraft/expr/pre/incr.md
Normal file
@@ -0,0 +1,27 @@
|
||||
[expr.pre.incr]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.pre.incr)
|
||||
|
||||
### 7.6.2 Unary expressions [[expr.unary]](expr.unary#expr.pre.incr)
|
||||
|
||||
#### 7.6.2.3 Increment and decrement [expr.pre.incr]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5390)
|
||||
|
||||
The operand of prefix ++ or -- shall not be of type cv bool[.](#1.sentence-1)
|
||||
|
||||
An operand with volatile-qualified type is deprecated;
|
||||
see [[depr.volatile.type]](depr.volatile.type "D.4 Deprecated volatile types")[.](#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"))[.](#1.sentence-3)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
For postfix increment and decrement, see [[expr.post.incr]](expr.post.incr "7.6.1.6 Increment and decrement")[.](#1.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
2215
cppdraft/expr/prim.md
Normal file
2215
cppdraft/expr/prim.md
Normal file
File diff suppressed because it is too large
Load Diff
63
cppdraft/expr/prim/fold.md
Normal file
63
cppdraft/expr/prim/fold.md
Normal file
@@ -0,0 +1,63 @@
|
||||
[expr.prim.fold]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#fold)
|
||||
|
||||
### 7.5.7 Fold expressions [expr.prim.fold]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3116)
|
||||
|
||||
A fold expression performs a fold of a
|
||||
pack ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates")) over a binary operator[.](#1.sentence-1)
|
||||
|
||||
[fold-expression:](#nt:fold-expression "7.5.7 Fold expressions [expr.prim.fold]")
|
||||
( [*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]") [*fold-operator*](#nt:fold-operator "7.5.7 Fold expressions [expr.prim.fold]") ... )
|
||||
( ... [*fold-operator*](#nt:fold-operator "7.5.7 Fold expressions [expr.prim.fold]") [*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]") [*fold-operator*](#nt:fold-operator "7.5.7 Fold expressions [expr.prim.fold]") ... [*fold-operator*](#nt:fold-operator "7.5.7 Fold expressions [expr.prim.fold]") [*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]") )
|
||||
|
||||
[fold-operator:](#nt:fold-operator "7.5.7 Fold expressions [expr.prim.fold]") one of
|
||||
+ - * / % ^ & | << >>
|
||||
+= -= *= /= %= ^= &= |= <<= >>= =
|
||||
== != < > <= >= && || , .* ->*
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3136)
|
||||
|
||||
An expression of the form(... *op* e) where *op* is a [*fold-operator*](#nt:fold-operator "7.5.7 Fold expressions [expr.prim.fold]") is called a [*unary left fold*](#def:unary_left_fold "7.5.7 Fold expressions [expr.prim.fold]")[.](#2.sentence-1)
|
||||
|
||||
An expression of the form(e *op* ...) where *op* is a [*fold-operator*](#nt:fold-operator "7.5.7 Fold expressions [expr.prim.fold]") is called a [*unary right fold*](#def:unary_right_fold "7.5.7 Fold expressions [expr.prim.fold]")[.](#2.sentence-2)
|
||||
|
||||
Unary left folds and unary right folds
|
||||
are collectively called [*unary folds*](#def:unary_fold "7.5.7 Fold expressions [expr.prim.fold]")[.](#2.sentence-3)
|
||||
|
||||
In a unary fold,
|
||||
the [*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]") shall contain an unexpanded pack ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates"))[.](#2.sentence-4)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3152)
|
||||
|
||||
An expression of the form(e1 *op1* ... *op2* e2) where *op1* and *op2* are [*fold-operator*](#nt:fold-operator "7.5.7 Fold expressions [expr.prim.fold]")*s* is called a [*binary fold*](#def:binary_fold "7.5.7 Fold expressions [expr.prim.fold]")[.](#3.sentence-1)
|
||||
|
||||
In a binary fold,*op1* and *op2* shall be the same [*fold-operator*](#nt:fold-operator "7.5.7 Fold expressions [expr.prim.fold]"),
|
||||
and either e1 shall contain an unexpanded pack
|
||||
or e2 shall contain an unexpanded pack,
|
||||
but not both[.](#3.sentence-2)
|
||||
|
||||
If e2 contains an unexpanded pack,
|
||||
the expression is called a [*binary left fold*](#def:binary_left_fold "7.5.7 Fold expressions [expr.prim.fold]")[.](#3.sentence-3)
|
||||
|
||||
If e1 contains an unexpanded pack,
|
||||
the expression is called a [*binary right fold*](#def:binary_right_fold "7.5.7 Fold expressions [expr.prim.fold]")[.](#3.sentence-4)
|
||||
|
||||
[*Example [1](#example-1)*: template<typename ...Args>bool f(Args ...args) {return (true && ... && args); // OK}template<typename ...Args>bool f(Args ...args) {return (args + ... + args); // error: both operands contain unexpanded packs} â *end example*]
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3184)
|
||||
|
||||
A fold expression is a pack expansion[.](#4.sentence-1)
|
||||
17
cppdraft/expr/prim/grammar.md
Normal file
17
cppdraft/expr/prim/grammar.md
Normal file
@@ -0,0 +1,17 @@
|
||||
[expr.prim.grammar]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#grammar)
|
||||
|
||||
### 7.5.1 Grammar [expr.prim.grammar]
|
||||
|
||||
[primary-expression:](#nt:primary-expression "7.5.1 Grammar [expr.prim.grammar]")
|
||||
[*literal*](lex.literal.kinds#nt:literal "5.13.1 Kinds of literals [lex.literal.kinds]")
|
||||
this
|
||||
( [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") )
|
||||
[*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]")
|
||||
[*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")
|
||||
[*fold-expression*](expr.prim.fold#nt:fold-expression "7.5.7 Fold expressions [expr.prim.fold]")
|
||||
[*requires-expression*](expr.prim.req.general#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]")
|
||||
[*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]")
|
||||
707
cppdraft/expr/prim/id.md
Normal file
707
cppdraft/expr/prim/id.md
Normal file
@@ -0,0 +1,707 @@
|
||||
[expr.prim.id]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#id)
|
||||
|
||||
### 7.5.5 Names [expr.prim.id]
|
||||
|
||||
#### [7.5.5.1](#general) General [[expr.prim.id.general]](expr.prim.id.general)
|
||||
|
||||
[id-expression:](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]")
|
||||
[*unqualified-id*](#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]")
|
||||
[*qualified-id*](#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]")
|
||||
[*pack-index-expression*](#nt:pack-index-expression "7.5.5.4 Pack indexing expression [expr.prim.pack.index]")
|
||||
|
||||
[1](#general-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1368)
|
||||
|
||||
An [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") is a restricted form of a[*primary-expression*](expr.prim.grammar#nt:primary-expression "7.5.1 Grammar [expr.prim.grammar]")[.](#general-1.sentence-1)
|
||||
|
||||
[*Note [1](#general-note-1)*:
|
||||
|
||||
An [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") can appear after[. and -> operators](expr.ref "7.6.1.5 Class member access [expr.ref]")[.](#general-1.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#general-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1378)
|
||||
|
||||
If an [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") E denotes
|
||||
a non-static non-type member of some class C at a point where
|
||||
the current class ([[expr.prim.this]](expr.prim.this "7.5.3 This")) is X and
|
||||
|
||||
- [(2.1)](#general-2.1)
|
||||
|
||||
E is potentially evaluated orC is X or a base class of X, and
|
||||
|
||||
- [(2.2)](#general-2.2)
|
||||
|
||||
E is not the [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") of
|
||||
a class member access expression ([[expr.ref]](expr.ref "7.6.1.5 Class member access")), and
|
||||
|
||||
- [(2.3)](#general-2.3)
|
||||
|
||||
E is not the [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") of
|
||||
a [*reflect-expression*](expr.reflect#nt:reflect-expression "7.6.2.10 The reflection operator [expr.reflect]") ([[expr.reflect]](expr.reflect "7.6.2.10 The reflection operator")), and
|
||||
|
||||
- [(2.4)](#general-2.4)
|
||||
|
||||
if E is a [*qualified-id*](#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]"),E is not the un-parenthesized operand of
|
||||
the unary & operator ([[expr.unary.op]](expr.unary.op "7.6.2.2 Unary operators")),
|
||||
|
||||
the [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") is transformed into
|
||||
a class member access expression using (*this) as the object expression[.](#general-2.sentence-1)
|
||||
|
||||
If this transformation occurs
|
||||
in the predicate of a precondition assertion of a constructor of X or a postcondition assertion of a destructor of X,
|
||||
the expression is ill-formed[.](#general-2.sentence-2)
|
||||
|
||||
[*Note [2](#general-note-2)*:
|
||||
|
||||
If C is not X or a base class of X,
|
||||
the class member access expression is ill-formed[.](#general-2.sentence-3)
|
||||
|
||||
Also, if the [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") occurs within
|
||||
a static or explicit object member function,
|
||||
the class member access is ill-formed[.](#general-2.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
This transformation does not apply in
|
||||
the template definition context ([[temp.dep.type]](temp.dep.type "13.8.3.2 Dependent types"))[.](#general-2.sentence-5)
|
||||
|
||||
[*Example [1](#general-example-1)*: struct C {bool b;
|
||||
C() pre(b) // error pre(&this->b) // OK pre(sizeof(b) > 0); // OK, b is not potentially evaluated.}; â *end example*]
|
||||
|
||||
[3](#general-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1423)
|
||||
|
||||
If an [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") E denotes
|
||||
a member M of an anonymous union ([[class.union.anon]](class.union.anon "11.5.2 Anonymous unions")) U:
|
||||
|
||||
- [(3.1)](#general-3.1)
|
||||
|
||||
If U is a non-static data member,E refers to M as a member of the lookup context of the terminal name of E (after any implicit transformation to
|
||||
a class member access expression)[.](#general-3.1.sentence-1)
|
||||
[*Example [2](#general-example-2)*:
|
||||
o.x is interpreted as o.u.x,
|
||||
where u names the anonymous union member[.](#general-3.1.sentence-2)
|
||||
â *end example*]
|
||||
|
||||
- [(3.2)](#general-3.2)
|
||||
|
||||
Otherwise, E is interpreted as a class member access ([[expr.ref]](expr.ref "7.6.1.5 Class member access"))
|
||||
that designates the member subobject M of
|
||||
the anonymous union variable for U[.](#general-3.2.sentence-1)
|
||||
[*Note [3](#general-note-3)*:
|
||||
Under this interpretation, E no longer denotes a non-static data member[.](#general-3.2.sentence-2)
|
||||
â *end note*]
|
||||
[*Example [3](#general-example-3)*:
|
||||
N::x is interpreted as N::u.x,
|
||||
where u names the anonymous union variable[.](#general-3.2.sentence-3)
|
||||
â *end example*]
|
||||
|
||||
[4](#general-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1449)
|
||||
|
||||
An [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") or [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") that designates a non-static data member or
|
||||
implicit object member function of a class can only be used:
|
||||
|
||||
- [(4.1)](#general-4.1)
|
||||
|
||||
as part of a class member access
|
||||
(after any implicit transformation (see above))
|
||||
in which the
|
||||
object expression
|
||||
refers to the member's class
|
||||
or a class derived from
|
||||
that class, or
|
||||
|
||||
- [(4.2)](#general-4.2)
|
||||
|
||||
to form a pointer to member ([[expr.unary.op]](expr.unary.op "7.6.2.2 Unary operators")), or
|
||||
|
||||
- [(4.3)](#general-4.3)
|
||||
|
||||
if that [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") or [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") designates a non-static data member
|
||||
and it appears in an unevaluated operand[.](#general-4.sentence-1)
|
||||
[*Example [4](#general-example-4)*: struct S {int m;};int i = sizeof(S::m); // OKint j = sizeof(S::m + 42); // OKint S::*k = &[:^^S::m:]; // OK â *end example*]
|
||||
|
||||
[5](#general-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1479)
|
||||
|
||||
For an [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") that denotes an overload set,
|
||||
overload resolution is performed
|
||||
to select a unique function ([[over.match]](over.match "12.2 Overload resolution"), [[over.over]](over.over "12.3 Address of an overload set"))[.](#general-5.sentence-1)
|
||||
|
||||
[*Note [4](#general-note-4)*:
|
||||
|
||||
A program cannot refer to a function
|
||||
with a trailing [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") whose [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") is not satisfied,
|
||||
because such functions are never selected by overload resolution[.](#general-5.sentence-2)
|
||||
|
||||
[*Example [5](#general-example-5)*: template<typename T> struct A {static void f(int) requires false;};
|
||||
|
||||
void g() { A<int>::f(0); // error: cannot call fvoid (*p1)(int) = A<int>::f; // error: cannot take the address of fdecltype(A<int>::f)* p2 = nullptr; // error: the type decltype(A<int>::f) is invalid}
|
||||
|
||||
In each case, the constraints of f are not satisfied[.](#general-5.sentence-3)
|
||||
|
||||
In the declaration of p2,
|
||||
those constraints need to be satisfied
|
||||
even thoughf is an [unevaluated operand](expr.context#def:unevaluated_operand "7.2.3 Context dependence [expr.context]")[.](#general-5.sentence-4)
|
||||
|
||||
â *end example*]
|
||||
|
||||
â *end note*]
|
||||
|
||||
#### [7.5.5.2](#unqual) Unqualified names [[expr.prim.id.unqual]](expr.prim.id.unqual)
|
||||
|
||||
[unqualified-id:](#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]")
|
||||
[*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]")
|
||||
[*operator-function-id*](over.oper.general#nt:operator-function-id "12.4.1 General [over.oper.general]")
|
||||
[*conversion-function-id*](class.conv.fct#nt:conversion-function-id "11.4.8.3 Conversion functions [class.conv.fct]")
|
||||
[*literal-operator-id*](over.literal#nt:literal-operator-id "12.6 User-defined literals [over.literal]")
|
||||
~ [*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]")
|
||||
~ [*computed-type-specifier*](dcl.type.simple#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]")
|
||||
[*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]")
|
||||
|
||||
[1](#unqual-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1521)
|
||||
|
||||
An [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") is only
|
||||
an [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") if it has
|
||||
been suitably declared ([[dcl]](dcl "9 Declarations"))
|
||||
or if it appears as part of a [*declarator-id*](dcl.decl.general#nt:declarator-id "9.3.1 General [dcl.decl.general]") ([[dcl.decl]](dcl.decl "9.3 Declarators"))[.](#unqual-1.sentence-1)
|
||||
|
||||
[*Note [1](#unqual-note-1)*:
|
||||
|
||||
For [*operator-function-id*](over.oper.general#nt:operator-function-id "12.4.1 General [over.oper.general]")*s*, see [[over.oper]](over.oper "12.4 Overloaded operators"); for[*conversion-function-id*](class.conv.fct#nt:conversion-function-id "11.4.8.3 Conversion functions [class.conv.fct]")*s*, see [[class.conv.fct]](class.conv.fct "11.4.8.3 Conversion functions"); for[*literal-operator-id*](over.literal#nt:literal-operator-id "12.6 User-defined literals [over.literal]")*s*, see [[over.literal]](over.literal "12.6 User-defined literals"); for[*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]")*s*, see [[temp.names]](temp.names "13.3 Names of template specializations")[.](#unqual-1.sentence-2)
|
||||
|
||||
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]") prefixed by ~ denotes the destructor of the type so named;
|
||||
see [[expr.prim.id.dtor]](#dtor "7.5.5.5 Destruction")[.](#unqual-1.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#unqual-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1537)
|
||||
|
||||
A [*component name*](#def:component_name "7.5.5.2 Unqualified names [expr.prim.id.unqual]") of an [*unqualified-id*](#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]") U is
|
||||
|
||||
- [(2.1)](#unqual-2.1)
|
||||
|
||||
U if it is a name or
|
||||
|
||||
- [(2.2)](#unqual-2.2)
|
||||
|
||||
the component name of
|
||||
the [*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]") or [*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]") of U, if any[.](#unqual-2.sentence-1)
|
||||
|
||||
[*Note [2](#unqual-note-2)*:
|
||||
|
||||
Other constructs that contain names to look up can have several
|
||||
component names ([[expr.prim.id.qual]](#qual "7.5.5.3 Qualified names"), [[dcl.type.simple]](dcl.type.simple "9.2.9.3 Simple type specifiers"), [[dcl.type.elab]](dcl.type.elab "9.2.9.5 Elaborated type specifiers"), [[dcl.mptr]](dcl.mptr "9.3.4.4 Pointers to members"), [[namespace.udecl]](namespace.udecl "9.10 The using declaration"), [[temp.param]](temp.param "13.2 Template parameters"), [[temp.names]](temp.names "13.3 Names of template specializations"), [[temp.res]](temp.res "13.8 Name resolution"))[.](#unqual-2.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
The [*terminal name*](#def:name,terminal "7.5.5.2 Unqualified names [expr.prim.id.unqual]") of a construct is
|
||||
the component name of that construct that appears lexically last[.](#unqual-2.sentence-3)
|
||||
|
||||
[3](#unqual-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1554)
|
||||
|
||||
The result is the entity denoted by
|
||||
the [*unqualified-id*](#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]") ([[basic.lookup.unqual]](basic.lookup.unqual "6.5.3 Unqualified name lookup"))[.](#unqual-3.sentence-1)
|
||||
|
||||
[4](#unqual-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1558)
|
||||
|
||||
If
|
||||
|
||||
- [(4.1)](#unqual-4.1)
|
||||
|
||||
the [*unqualified-id*](#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]") appears in a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") at program point P,
|
||||
|
||||
- [(4.2)](#unqual-4.2)
|
||||
|
||||
the entity is a local entity ([[basic.pre]](basic.pre "6.1 Preamble"))
|
||||
or 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")),
|
||||
|
||||
- [(4.3)](#unqual-4.3)
|
||||
|
||||
naming the entity within the [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") of
|
||||
the innermost enclosing [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") of P,
|
||||
but not in an unevaluated operand, would refer to an entity captured by copy
|
||||
in some intervening [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]"), and
|
||||
|
||||
- [(4.4)](#unqual-4.4)
|
||||
|
||||
P is in the function parameter scope,
|
||||
but not the [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]"),
|
||||
of the innermost such [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") E,
|
||||
|
||||
then
|
||||
the type of the expression is
|
||||
the type of a class member access expression ([[expr.ref]](expr.ref "7.6.1.5 Class member access"))
|
||||
naming the non-static data member
|
||||
that would be declared for such a capture
|
||||
in the object parameter ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")) of the function call operator of E[.](#unqual-4.sentence-1)
|
||||
|
||||
[*Note [3](#unqual-note-3)*:
|
||||
|
||||
If E is not declared mutable,
|
||||
the type of such an identifier will typically be const qualified[.](#unqual-4.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#unqual-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1589)
|
||||
|
||||
Otherwise,
|
||||
if the [*unqualified-id*](#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]") names a coroutine parameter,
|
||||
the type of the expression is
|
||||
that of the copy of the parameter ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4 Coroutine definitions")),
|
||||
and the result is that copy[.](#unqual-5.sentence-1)
|
||||
|
||||
[6](#unqual-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1597)
|
||||
|
||||
Otherwise,
|
||||
if the [*unqualified-id*](#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]") names a result binding ([[dcl.contract.res]](dcl.contract.res "9.4.2 Referring to the result object"))
|
||||
attached to a function *f* with return type U,
|
||||
|
||||
- [(6.1)](#unqual-6.1)
|
||||
|
||||
if U is âreference to Tâ,
|
||||
then the type of the expression isconst T;
|
||||
|
||||
- [(6.2)](#unqual-6.2)
|
||||
|
||||
otherwise,
|
||||
the type of the expression is const U[.](#unqual-6.sentence-1)
|
||||
|
||||
[7](#unqual-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1613)
|
||||
|
||||
Otherwise,
|
||||
if the [*unqualified-id*](#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]") appears in the predicate of a contract assertion C ([[basic.contract]](basic.contract "6.11 Contract assertions"))
|
||||
and the entity is
|
||||
|
||||
- [(7.1)](#unqual-7.1)
|
||||
|
||||
a variable
|
||||
declared outside of C of object type T,
|
||||
|
||||
- [(7.2)](#unqual-7.2)
|
||||
|
||||
a variable or template parameter
|
||||
declared outside of C of type âreference to Tâ, or
|
||||
|
||||
- [(7.3)](#unqual-7.3)
|
||||
|
||||
a structured binding
|
||||
of type T whose corresponding variable
|
||||
is declared outside of C,
|
||||
|
||||
then the type of the expression is const T[.](#unqual-7.sentence-1)
|
||||
|
||||
[8](#unqual-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1635)
|
||||
|
||||
[*Example [1](#unqual-example-1)*: int n = 0;struct X { bool m(); };
|
||||
|
||||
struct Y {int z = 0; void f(int i, int* p, int& r, X x, X* px) pre (++n) // error: attempting to modify const lvalue pre (++i) // error: attempting to modify const lvalue pre (++(*p)) // OK pre (++r) // error: attempting to modify const lvalue pre (x.m()) // error: calling non-const member function pre (px->m()) // OK pre ([=,&i,*this] mutable {++n; // error: attempting to modify const lvalue++i; // error: attempting to modify const lvalue++p; // OK, refers to member of closure type++r; // OK, refers to non-reference member of closure type++this->z; // OK, captured *this++z; // OK, captured *thisint j = 17; [&]{int k = 34; ++i; // error: attempting to modify const lvalue++j; // OK++k; // OK}(); return true; }()); template <int N, int& R, int* P>void g() pre(++N) // error: attempting to modify prvalue pre(++R) // error: attempting to modify const lvalue pre(++(*P)); // OKint h() post(r : ++r) // error: attempting to modify const lvalue post(r: [=] mutable {++r; // OK, refers to member of closure typereturn true; }()); int& k() post(r : ++r); // error: attempting to modify const lvalue}; â *end example*]
|
||||
|
||||
[9](#unqual-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1687)
|
||||
|
||||
Otherwise, if the entity is a template parameter object for
|
||||
a template parameter of type T ([[temp.param]](temp.param "13.2 Template parameters")),
|
||||
the type of the expression is const T[.](#unqual-9.sentence-1)
|
||||
|
||||
[10](#unqual-10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1692)
|
||||
|
||||
In all other cases, the type of the expression is the type of the entity[.](#unqual-10.sentence-1)
|
||||
|
||||
[11](#unqual-11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1695)
|
||||
|
||||
[*Note [4](#unqual-note-4)*:
|
||||
|
||||
The type will be adjusted as described in [[expr.type]](expr.type "7.2.2 Type") if it is cv-qualified or is a reference type[.](#unqual-11.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[12](#unqual-12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1701)
|
||||
|
||||
The expression is an xvalue if it is move-eligible (see below);
|
||||
an lvalue
|
||||
if the entity is a
|
||||
function,
|
||||
variable,
|
||||
structured binding ([[dcl.struct.bind]](dcl.struct.bind "9.7 Structured binding declarations")),
|
||||
result binding ([[dcl.contract.res]](dcl.contract.res "9.4.2 Referring to the result object")),
|
||||
data member, or
|
||||
template parameter object;
|
||||
and a prvalue otherwise ([[basic.lval]](basic.lval "7.2.1 Value category"));
|
||||
it is a bit-field if the identifier designates a bit-field[.](#unqual-12.sentence-1)
|
||||
|
||||
[13](#unqual-13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1714)
|
||||
|
||||
If an [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") E appears in the predicate of
|
||||
a function contract assertion attached to a function *f* and denotes
|
||||
a function parameter of *f* and the implementation introduces any temporary objects
|
||||
to hold the value of that parameter as specified in [[class.temporary]](class.temporary "6.8.7 Temporary objects"),
|
||||
|
||||
- [(13.1)](#unqual-13.1)
|
||||
|
||||
if the contract assertion
|
||||
is a precondition assertion
|
||||
and the evaluation of the precondition assertion
|
||||
is sequenced before the initialization of the parameter object,E refers to the most recently initialized such temporary object, and
|
||||
|
||||
- [(13.2)](#unqual-13.2)
|
||||
|
||||
if the contract assertion
|
||||
is a postcondition assertion,
|
||||
it is unspecified whether E refers to
|
||||
one of the temporary objects or the parameter object;
|
||||
the choice is consistent within a single evaluation of a postcondition assertion[.](#unqual-13.sentence-1)
|
||||
|
||||
[14](#unqual-14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1737)
|
||||
|
||||
If an [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") E names a result binding
|
||||
in a postcondition assertion
|
||||
and the implementation introduces any temporary objects
|
||||
to hold the result object as specified in [[class.temporary]](class.temporary "6.8.7 Temporary objects"),
|
||||
and the postcondition assertion
|
||||
is sequenced before the initialization of the result object ([[expr.call]](expr.call "7.6.1.3 Function call")),E refers to the most recently initialized such temporary object[.](#unqual-14.sentence-1)
|
||||
|
||||
[*Example [2](#unqual-example-2)*: void f() {float x, &r = x; [=]() -> decltype((x)) { // lambda returns float const& because this lambda is not mutable and// x is an lvaluedecltype(x) y1; // y1 has type floatdecltype((x)) y2 = y1; // y2 has type float const&decltype(r) r1 = y1; // r1 has type float&decltype((r)) r2 = y2; // r2 has type float const&return y2; }; [=](decltype((x)) y) {decltype((x)) z = x; // OK, y has type float&, z has type float const&}; [=] {[](decltype((x)) y) {}; // OK, lambda takes a parameter of type float const&[x=1](decltype((x)) y) {decltype((x)) z = x; // OK, y has type int&, z has type int const&}; };} â *end example*]
|
||||
|
||||
[15](#unqual-15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1777)
|
||||
|
||||
An [*implicitly movable entity*](#def:entity,implicitly_movable "7.5.5.2 Unqualified names [expr.prim.id.unqual]") is
|
||||
a variable with automatic storage duration
|
||||
that is either a non-volatile object or
|
||||
an rvalue reference to a non-volatile object type[.](#unqual-15.sentence-1)
|
||||
|
||||
An [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") or[*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") ([[expr.prim.splice]](expr.prim.splice "7.5.9 Expression splicing"))
|
||||
is [*move-eligible*](#def:move-eligible "7.5.5.2 Unqualified names [expr.prim.id.unqual]") if
|
||||
|
||||
- [(15.1)](#unqual-15.1)
|
||||
|
||||
it designates an implicitly movable entity,
|
||||
|
||||
- [(15.2)](#unqual-15.2)
|
||||
|
||||
it is the (possibly parenthesized)
|
||||
operand of a return ([[stmt.return]](stmt.return "8.8.4 The return statement")) orco_return ([[stmt.return.coroutine]](stmt.return.coroutine "8.8.5 The co_return statement")) statement or
|
||||
of a [*throw-expression*](expr.throw#nt:throw-expression "7.6.18 Throwing an exception [expr.throw]") ([[expr.throw]](expr.throw "7.6.18 Throwing an exception")), and
|
||||
|
||||
- [(15.3)](#unqual-15.3)
|
||||
|
||||
each intervening scope between
|
||||
the declaration of the entity and
|
||||
the innermost enclosing scope of the expression
|
||||
is a block scope and,
|
||||
for a [*throw-expression*](expr.throw#nt:throw-expression "7.6.18 Throwing an exception [expr.throw]"),
|
||||
is not the block scope of
|
||||
a [*try-block*](except.pre#nt:try-block "14.1 Preamble [except.pre]") or [*function-try-block*](except.pre#nt:function-try-block "14.1 Preamble [except.pre]")[.](#unqual-15.sentence-2)
|
||||
|
||||
#### [7.5.5.3](#qual) Qualified names [[expr.prim.id.qual]](expr.prim.id.qual)
|
||||
|
||||
[qualified-id:](#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]")
|
||||
[*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") templateopt [*unqualified-id*](#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]")
|
||||
|
||||
[nested-name-specifier:](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")
|
||||
::
|
||||
[*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]") ::
|
||||
[*namespace-name*](namespace.def.general#nt:namespace-name "9.9.2.1 General [namespace.def.general]") ::
|
||||
[*computed-type-specifier*](dcl.type.simple#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") ::
|
||||
[*splice-scope-specifier*](#nt:splice-scope-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") ::
|
||||
[*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") ::
|
||||
[*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") templateopt [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]") ::
|
||||
|
||||
[splice-scope-specifier:](#nt:splice-scope-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")
|
||||
[*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]")
|
||||
templateopt [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]")
|
||||
|
||||
[1](#qual-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1832)
|
||||
|
||||
The component names of a [*qualified-id*](#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") are those of
|
||||
its [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") and [*unqualified-id*](#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]")[.](#qual-1.sentence-1)
|
||||
|
||||
The component names of a [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") are
|
||||
its [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") (if any) and those of its[*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]"),[*namespace-name*](namespace.def.general#nt:namespace-name "9.9.2.1 General [namespace.def.general]"),[*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]"), and/or[*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")[.](#qual-1.sentence-2)
|
||||
|
||||
[2](#qual-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1843)
|
||||
|
||||
A [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]") or[*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]") that is not followed by :: is never interpreted as part of a [*splice-scope-specifier*](#nt:splice-scope-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")[.](#qual-2.sentence-1)
|
||||
|
||||
The keyword template may only be omitted
|
||||
from the formtemplateopt [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]") :: when the [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]") is preceded by typename[.](#qual-2.sentence-2)
|
||||
|
||||
[*Example [1](#qual-example-1)*: template<int V>struct TCls {static constexpr int s = V; using type = int;};
|
||||
|
||||
int v1 = [:^^TCls<1>:]::s;int v2 = template [:^^TCls:]<2>::s; // OK, template binds to [*splice-scope-specifier*](#nt:splice-scope-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")typename [:^^TCls:]<3>::type v3 = 3; // OK, typename binds to the qualified nametemplate [:^^TCls:]<3>::type v4 = 4; // OK, template binds to the [*splice-scope-specifier*](#nt:splice-scope-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")typename template [:^^TCls:]<3>::type v5 = 5; // OK, same as v3[:^^TCls:]<3>::type v6 = 6; // error: unexpected < â *end example*]
|
||||
|
||||
[3](#qual-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1870)
|
||||
|
||||
A [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") is [*declarative*](#def:declarative "7.5.5.3 Qualified names [expr.prim.id.qual]") if it is part of
|
||||
|
||||
- [(3.1)](#qual-3.1)
|
||||
|
||||
a [*class-head-name*](class.pre#nt:class-head-name "11.1 Preamble [class.pre]"),
|
||||
|
||||
- [(3.2)](#qual-3.2)
|
||||
|
||||
an [*enum-head-name*](dcl.enum#nt:enum-head-name "9.8.1 Enumeration declarations [dcl.enum]"),
|
||||
|
||||
- [(3.3)](#qual-3.3)
|
||||
|
||||
a [*qualified-id*](#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") that is the [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") of a [*declarator-id*](dcl.decl.general#nt:declarator-id "9.3.1 General [dcl.decl.general]"), or
|
||||
|
||||
- [(3.4)](#qual-3.4)
|
||||
|
||||
a declarative [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")[.](#qual-3.sentence-1)
|
||||
|
||||
A declarative [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") shall not have a [*computed-type-specifier*](dcl.type.simple#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") or
|
||||
a [*splice-scope-specifier*](#nt:splice-scope-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")[.](#qual-3.sentence-2)
|
||||
|
||||
A declaration that uses a declarative [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") shall be a friend declaration or
|
||||
inhabit a scope that contains the entity being redeclared or specialized[.](#qual-3.sentence-3)
|
||||
|
||||
[4](#qual-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1890)
|
||||
|
||||
The entity designated by a [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") is determined as follows:
|
||||
|
||||
- [(4.1)](#qual-4.1)
|
||||
|
||||
The [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") :: designates
|
||||
the global namespace[.](#qual-4.1.sentence-1)
|
||||
|
||||
- [(4.2)](#qual-4.2)
|
||||
|
||||
A [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") with a [*computed-type-specifier*](dcl.type.simple#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") designates the same type designated by the [*computed-type-specifier*](dcl.type.simple#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]"),
|
||||
which shall be a class or enumeration type[.](#qual-4.2.sentence-1)
|
||||
|
||||
- [(4.3)](#qual-4.3)
|
||||
|
||||
For a [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") of
|
||||
the form [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]") ::,
|
||||
the [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]") shall designate
|
||||
a class or enumeration type or a namespace[.](#qual-4.3.sentence-1)
|
||||
The [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") designates the same entity
|
||||
as the [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]")[.](#qual-4.3.sentence-2)
|
||||
|
||||
- [(4.4)](#qual-4.4)
|
||||
|
||||
For a [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") of
|
||||
the formtemplateopt [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]") ::,
|
||||
the [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]") of
|
||||
the [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]") shall designate
|
||||
a class template or an alias template T[.](#qual-4.4.sentence-1)
|
||||
Letting S be the specialization of T corresponding to the template argument list of
|
||||
the [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]"),S shall either be a class template specialization or
|
||||
an alias template specialization that denotes a class or enumeration type[.](#qual-4.4.sentence-2)
|
||||
The [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") designates the underlying entity of S[.](#qual-4.4.sentence-3)
|
||||
|
||||
- [(4.5)](#qual-4.5)
|
||||
|
||||
If a [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") N is declarative and
|
||||
has a [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]") with a template argument list A that involves a template parameter,
|
||||
let T be the template nominated by N without A[.](#qual-4.5.sentence-1)
|
||||
T shall be a class template[.](#qual-4.5.sentence-2)
|
||||
|
||||
* [(4.5.1)](#qual-4.5.1)
|
||||
|
||||
If A is the template argument list ([[temp.arg]](temp.arg "13.4 Template arguments")) of
|
||||
the corresponding [*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]") H ([[temp.mem]](temp.mem "13.7.3 Member templates")),N designates the primary template of T;H shall be equivalent to
|
||||
the [*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]") of T ([[temp.over.link]](temp.over.link "13.7.7.2 Function template overloading"))[.](#qual-4.5.1.sentence-1)
|
||||
|
||||
* [(4.5.2)](#qual-4.5.2)
|
||||
|
||||
Otherwise, N designates the partial specialization ([[temp.spec.partial]](temp.spec.partial "13.7.6 Partial specialization")) of T whose template argument list is equivalent to A ([[temp.over.link]](temp.over.link "13.7.7.2 Function template overloading"));
|
||||
the program is ill-formed if no such partial specialization exists[.](#qual-4.5.2.sentence-1)
|
||||
|
||||
- [(4.6)](#qual-4.6)
|
||||
|
||||
Any other [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") designates
|
||||
the entity denotes by its[*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]"),[*namespace-name*](namespace.def.general#nt:namespace-name "9.9.2.1 General [namespace.def.general]"),[*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]"), or[*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]")[.](#qual-4.6.sentence-1)
|
||||
If the [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") is not declarative,
|
||||
the entity shall not be a template[.](#qual-4.6.sentence-2)
|
||||
|
||||
[5](#qual-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1951)
|
||||
|
||||
A [*qualified-id*](#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") shall not be of the form[*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") templateopt ~[*computed-type-specifier*](dcl.type.simple#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") nor of the form[*computed-type-specifier*](dcl.type.simple#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") :: ~ [*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]")[.](#qual-5.sentence-1)
|
||||
|
||||
[6](#qual-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1958)
|
||||
|
||||
The result of a [*qualified-id*](#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") Q is
|
||||
the entity it denotes ([[basic.lookup.qual]](basic.lookup.qual "6.5.5 Qualified name lookup"))[.](#qual-6.sentence-1)
|
||||
|
||||
[7](#qual-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1962)
|
||||
|
||||
If Q appears
|
||||
in the predicate of a contract assertion C ([[basic.contract]](basic.contract "6.11 Contract assertions"))
|
||||
and the entity is
|
||||
|
||||
- [(7.1)](#qual-7.1)
|
||||
|
||||
a variable
|
||||
declared outside of C of object type T,
|
||||
|
||||
- [(7.2)](#qual-7.2)
|
||||
|
||||
a variable
|
||||
declared outside of C of type âreference to Tâ, or
|
||||
|
||||
- [(7.3)](#qual-7.3)
|
||||
|
||||
a structured binding of type T whose corresponding variable
|
||||
is declared outside of C,
|
||||
|
||||
then the type of the expression is const T[.](#qual-7.sentence-1)
|
||||
|
||||
[8](#qual-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1983)
|
||||
|
||||
Otherwise, the type of the expression is the type of the result[.](#qual-8.sentence-1)
|
||||
|
||||
[9](#qual-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1986)
|
||||
|
||||
The result is an lvalue if the member is
|
||||
|
||||
- [(9.1)](#qual-9.1)
|
||||
|
||||
a function other than a non-static member function,
|
||||
|
||||
- [(9.2)](#qual-9.2)
|
||||
|
||||
a non-static member function
|
||||
if Q is the operand of a unary & operator,
|
||||
|
||||
- [(9.3)](#qual-9.3)
|
||||
|
||||
a variable,
|
||||
|
||||
- [(9.4)](#qual-9.4)
|
||||
|
||||
a structured binding ([[dcl.struct.bind]](dcl.struct.bind "9.7 Structured binding declarations")), or
|
||||
|
||||
- [(9.5)](#qual-9.5)
|
||||
|
||||
a data member,
|
||||
|
||||
and a prvalue otherwise[.](#qual-9.sentence-1)
|
||||
|
||||
#### [7.5.5.4](#expr.prim.pack.index) Pack indexing expression [[expr.prim.pack.index]](expr.prim.pack.index)
|
||||
|
||||
[pack-index-expression:](#nt:pack-index-expression "7.5.5.4 Pack indexing expression [expr.prim.pack.index]")
|
||||
[*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") ... [ [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]") ]
|
||||
|
||||
[1](#expr.prim.pack.index-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2010)
|
||||
|
||||
The [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") P in a [*pack-index-expression*](#nt:pack-index-expression "7.5.5.4 Pack indexing expression [expr.prim.pack.index]") shall be an [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") that denotes a pack[.](#expr.prim.pack.index-1.sentence-1)
|
||||
|
||||
[2](#expr.prim.pack.index-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2014)
|
||||
|
||||
The [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]") shall be
|
||||
a converted constant expression ([[expr.const]](expr.const "7.7 Constant expressions")) of type std::size_t whose value V, termed the index,
|
||||
is such that 0â¤V<sizeof...(P)[.](#expr.prim.pack.index-2.sentence-1)
|
||||
|
||||
[3](#expr.prim.pack.index-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2020)
|
||||
|
||||
A [*pack-index-expression*](#nt:pack-index-expression "7.5.5.4 Pack indexing expression [expr.prim.pack.index]") is a pack expansion ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates"))[.](#expr.prim.pack.index-3.sentence-1)
|
||||
|
||||
[4](#expr.prim.pack.index-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2023)
|
||||
|
||||
[*Note [1](#expr.prim.pack.index-note-1)*:
|
||||
|
||||
A [*pack-index-expression*](#nt:pack-index-expression "7.5.5.4 Pack indexing expression [expr.prim.pack.index]") denotes
|
||||
the Vth element of the pack[.](#expr.prim.pack.index-4.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
#### [7.5.5.5](#dtor) Destruction [[expr.prim.id.dtor]](expr.prim.id.dtor)
|
||||
|
||||
[1](#dtor-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2031)
|
||||
|
||||
An [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") that denotes the destructor of a type T names the destructor of T if T is a class type ([[class.dtor]](class.dtor "11.4.7 Destructors")),
|
||||
otherwise the [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") is said
|
||||
to name a [*pseudo-destructor*](#def:pseudo-destructor "7.5.5.5 Destruction [expr.prim.id.dtor]")[.](#dtor-1.sentence-1)
|
||||
|
||||
[2](#dtor-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2040)
|
||||
|
||||
If the [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") names a pseudo-destructor,T shall be a scalar type and
|
||||
the [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") shall appear
|
||||
as the right operand of a class member access ([[expr.ref]](expr.ref "7.6.1.5 Class member access")) that forms
|
||||
the [*postfix-expression*](expr.post.general#nt:postfix-expression "7.6.1.1 General [expr.post.general]") of a function call ([[expr.call]](expr.call "7.6.1.3 Function call"))[.](#dtor-2.sentence-1)
|
||||
|
||||
[*Note [1](#dtor-note-1)*:
|
||||
|
||||
Such a call ends the lifetime of the object ([[expr.call]](expr.call "7.6.1.3 Function call"), [[basic.life]](basic.life "6.8.4 Lifetime"))[.](#dtor-2.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#dtor-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2050)
|
||||
|
||||
[*Example [1](#dtor-example-1)*: struct C { };void f() { C * pc = new C; using C2 = C;
|
||||
pc->C::~C2(); // OK, destroys *pc C().C::~C(); // undefined behavior: temporary of type C destroyed twiceusing T = int; 0 .T::~T(); // OK, no effect0.T::~T(); // error: 0.T is a [*user-defined-floating-point-literal*](lex.ext#nt:user-defined-floating-point-literal "5.13.9 User-defined literals [lex.ext]") ([[lex.ext]](lex.ext "5.13.9 User-defined literals"))} â *end example*]
|
||||
39
cppdraft/expr/prim/id/dtor.md
Normal file
39
cppdraft/expr/prim/id/dtor.md
Normal file
@@ -0,0 +1,39 @@
|
||||
[expr.prim.id.dtor]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#id.dtor)
|
||||
|
||||
### 7.5.5 Names [[expr.prim.id]](expr.prim.id#dtor)
|
||||
|
||||
#### 7.5.5.5 Destruction [expr.prim.id.dtor]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2031)
|
||||
|
||||
An [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") that denotes the destructor of a type T names the destructor of T if T is a class type ([[class.dtor]](class.dtor "11.4.7 Destructors")),
|
||||
otherwise the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") is said
|
||||
to name a [*pseudo-destructor*](#def:pseudo-destructor "7.5.5.5 Destruction [expr.prim.id.dtor]")[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2040)
|
||||
|
||||
If the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") names a pseudo-destructor,T shall be a scalar type and
|
||||
the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") shall appear
|
||||
as the right operand of a class member access ([[expr.ref]](expr.ref "7.6.1.5 Class member access")) that forms
|
||||
the [*postfix-expression*](expr.post.general#nt:postfix-expression "7.6.1.1 General [expr.post.general]") of a function call ([[expr.call]](expr.call "7.6.1.3 Function call"))[.](#2.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
Such a call ends the lifetime of the object ([[expr.call]](expr.call "7.6.1.3 Function call"), [[basic.life]](basic.life "6.8.4 Lifetime"))[.](#2.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2050)
|
||||
|
||||
[*Example [1](#example-1)*: struct C { };void f() { C * pc = new C; using C2 = C;
|
||||
pc->C::~C2(); // OK, destroys *pc C().C::~C(); // undefined behavior: temporary of type C destroyed twiceusing T = int; 0 .T::~T(); // OK, no effect0.T::~T(); // error: 0.T is a [*user-defined-floating-point-literal*](lex.ext#nt:user-defined-floating-point-literal "5.13.9 User-defined literals [lex.ext]") ([[lex.ext]](lex.ext "5.13.9 User-defined literals"))} â *end example*]
|
||||
161
cppdraft/expr/prim/id/general.md
Normal file
161
cppdraft/expr/prim/id/general.md
Normal file
@@ -0,0 +1,161 @@
|
||||
[expr.prim.id.general]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#id.general)
|
||||
|
||||
### 7.5.5 Names [[expr.prim.id]](expr.prim.id#general)
|
||||
|
||||
#### 7.5.5.1 General [expr.prim.id.general]
|
||||
|
||||
[id-expression:](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]")
|
||||
[*unqualified-id*](expr.prim.id.unqual#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]")
|
||||
[*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]")
|
||||
[*pack-index-expression*](expr.prim.pack.index#nt:pack-index-expression "7.5.5.4 Pack indexing expression [expr.prim.pack.index]")
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1368)
|
||||
|
||||
An [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") is a restricted form of a[*primary-expression*](expr.prim.grammar#nt:primary-expression "7.5.1 Grammar [expr.prim.grammar]")[.](#1.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
An [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") can appear after[. and -> operators](expr.ref "7.6.1.5 Class member access [expr.ref]")[.](#1.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1378)
|
||||
|
||||
If an [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") E denotes
|
||||
a non-static non-type member of some class C at a point where
|
||||
the current class ([[expr.prim.this]](expr.prim.this "7.5.3 This")) is X and
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
E is potentially evaluated orC is X or a base class of X, and
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
E is not the [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") of
|
||||
a class member access expression ([[expr.ref]](expr.ref "7.6.1.5 Class member access")), and
|
||||
|
||||
- [(2.3)](#2.3)
|
||||
|
||||
E is not the [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") of
|
||||
a [*reflect-expression*](expr.reflect#nt:reflect-expression "7.6.2.10 The reflection operator [expr.reflect]") ([[expr.reflect]](expr.reflect "7.6.2.10 The reflection operator")), and
|
||||
|
||||
- [(2.4)](#2.4)
|
||||
|
||||
if E is a [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]"),E is not the un-parenthesized operand of
|
||||
the unary & operator ([[expr.unary.op]](expr.unary.op "7.6.2.2 Unary operators")),
|
||||
|
||||
the [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") is transformed into
|
||||
a class member access expression using (*this) as the object expression[.](#2.sentence-1)
|
||||
|
||||
If this transformation occurs
|
||||
in the predicate of a precondition assertion of a constructor of X or a postcondition assertion of a destructor of X,
|
||||
the expression is ill-formed[.](#2.sentence-2)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
If C is not X or a base class of X,
|
||||
the class member access expression is ill-formed[.](#2.sentence-3)
|
||||
|
||||
Also, if the [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") occurs within
|
||||
a static or explicit object member function,
|
||||
the class member access is ill-formed[.](#2.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
This transformation does not apply in
|
||||
the template definition context ([[temp.dep.type]](temp.dep.type "13.8.3.2 Dependent types"))[.](#2.sentence-5)
|
||||
|
||||
[*Example [1](#example-1)*: struct C {bool b;
|
||||
C() pre(b) // error pre(&this->b) // OK pre(sizeof(b) > 0); // OK, b is not potentially evaluated.}; â *end example*]
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1423)
|
||||
|
||||
If an [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") E denotes
|
||||
a member M of an anonymous union ([[class.union.anon]](class.union.anon "11.5.2 Anonymous unions")) U:
|
||||
|
||||
- [(3.1)](#3.1)
|
||||
|
||||
If U is a non-static data member,E refers to M as a member of the lookup context of the terminal name of E (after any implicit transformation to
|
||||
a class member access expression)[.](#3.1.sentence-1)
|
||||
[*Example [2](#example-2)*:
|
||||
o.x is interpreted as o.u.x,
|
||||
where u names the anonymous union member[.](#3.1.sentence-2)
|
||||
â *end example*]
|
||||
|
||||
- [(3.2)](#3.2)
|
||||
|
||||
Otherwise, E is interpreted as a class member access ([[expr.ref]](expr.ref "7.6.1.5 Class member access"))
|
||||
that designates the member subobject M of
|
||||
the anonymous union variable for U[.](#3.2.sentence-1)
|
||||
[*Note [3](#note-3)*:
|
||||
Under this interpretation, E no longer denotes a non-static data member[.](#3.2.sentence-2)
|
||||
â *end note*]
|
||||
[*Example [3](#example-3)*:
|
||||
N::x is interpreted as N::u.x,
|
||||
where u names the anonymous union variable[.](#3.2.sentence-3)
|
||||
â *end example*]
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1449)
|
||||
|
||||
An [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") or [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") that designates a non-static data member or
|
||||
implicit object member function of a class can only be used:
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
as part of a class member access
|
||||
(after any implicit transformation (see above))
|
||||
in which the
|
||||
object expression
|
||||
refers to the member's class
|
||||
or a class derived from
|
||||
that class, or
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
to form a pointer to member ([[expr.unary.op]](expr.unary.op "7.6.2.2 Unary operators")), or
|
||||
|
||||
- [(4.3)](#4.3)
|
||||
|
||||
if that [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") or [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") designates a non-static data member
|
||||
and it appears in an unevaluated operand[.](#4.sentence-1)
|
||||
[*Example [4](#example-4)*: struct S {int m;};int i = sizeof(S::m); // OKint j = sizeof(S::m + 42); // OKint S::*k = &[:^^S::m:]; // OK â *end example*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1479)
|
||||
|
||||
For an [*id-expression*](#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") that denotes an overload set,
|
||||
overload resolution is performed
|
||||
to select a unique function ([[over.match]](over.match "12.2 Overload resolution"), [[over.over]](over.over "12.3 Address of an overload set"))[.](#5.sentence-1)
|
||||
|
||||
[*Note [4](#note-4)*:
|
||||
|
||||
A program cannot refer to a function
|
||||
with a trailing [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") whose [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") is not satisfied,
|
||||
because such functions are never selected by overload resolution[.](#5.sentence-2)
|
||||
|
||||
[*Example [5](#example-5)*: template<typename T> struct A {static void f(int) requires false;};
|
||||
|
||||
void g() { A<int>::f(0); // error: cannot call fvoid (*p1)(int) = A<int>::f; // error: cannot take the address of fdecltype(A<int>::f)* p2 = nullptr; // error: the type decltype(A<int>::f) is invalid}
|
||||
|
||||
In each case, the constraints of f are not satisfied[.](#5.sentence-3)
|
||||
|
||||
In the declaration of p2,
|
||||
those constraints need to be satisfied
|
||||
even thoughf is an [unevaluated operand](expr.context#def:unevaluated_operand "7.2.3 Context dependence [expr.context]")[.](#5.sentence-4)
|
||||
|
||||
â *end example*]
|
||||
|
||||
â *end note*]
|
||||
211
cppdraft/expr/prim/id/qual.md
Normal file
211
cppdraft/expr/prim/id/qual.md
Normal file
@@ -0,0 +1,211 @@
|
||||
[expr.prim.id.qual]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#id.qual)
|
||||
|
||||
### 7.5.5 Names [[expr.prim.id]](expr.prim.id#qual)
|
||||
|
||||
#### 7.5.5.3 Qualified names [expr.prim.id.qual]
|
||||
|
||||
[qualified-id:](#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]")
|
||||
[*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") templateopt [*unqualified-id*](expr.prim.id.unqual#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]")
|
||||
|
||||
[nested-name-specifier:](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")
|
||||
::
|
||||
[*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]") ::
|
||||
[*namespace-name*](namespace.def.general#nt:namespace-name "9.9.2.1 General [namespace.def.general]") ::
|
||||
[*computed-type-specifier*](dcl.type.simple#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") ::
|
||||
[*splice-scope-specifier*](#nt:splice-scope-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") ::
|
||||
[*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") ::
|
||||
[*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") templateopt [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]") ::
|
||||
|
||||
[splice-scope-specifier:](#nt:splice-scope-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")
|
||||
[*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]")
|
||||
templateopt [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]")
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1832)
|
||||
|
||||
The component names of a [*qualified-id*](#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") are those of
|
||||
its [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") and [*unqualified-id*](expr.prim.id.unqual#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]")[.](#1.sentence-1)
|
||||
|
||||
The component names of a [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") are
|
||||
its [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") (if any) and those of its[*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]"),[*namespace-name*](namespace.def.general#nt:namespace-name "9.9.2.1 General [namespace.def.general]"),[*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]"), and/or[*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")[.](#1.sentence-2)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1843)
|
||||
|
||||
A [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]") or[*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]") that is not followed by :: is never interpreted as part of a [*splice-scope-specifier*](#nt:splice-scope-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")[.](#2.sentence-1)
|
||||
|
||||
The keyword template may only be omitted
|
||||
from the formtemplateopt [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]") :: when the [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]") is preceded by typename[.](#2.sentence-2)
|
||||
|
||||
[*Example [1](#example-1)*: template<int V>struct TCls {static constexpr int s = V; using type = int;};
|
||||
|
||||
int v1 = [:^^TCls<1>:]::s;int v2 = template [:^^TCls:]<2>::s; // OK, template binds to [*splice-scope-specifier*](#nt:splice-scope-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")typename [:^^TCls:]<3>::type v3 = 3; // OK, typename binds to the qualified nametemplate [:^^TCls:]<3>::type v4 = 4; // OK, template binds to the [*splice-scope-specifier*](#nt:splice-scope-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")typename template [:^^TCls:]<3>::type v5 = 5; // OK, same as v3[:^^TCls:]<3>::type v6 = 6; // error: unexpected < â *end example*]
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1870)
|
||||
|
||||
A [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") is [*declarative*](#def:declarative "7.5.5.3 Qualified names [expr.prim.id.qual]") if it is part of
|
||||
|
||||
- [(3.1)](#3.1)
|
||||
|
||||
a [*class-head-name*](class.pre#nt:class-head-name "11.1 Preamble [class.pre]"),
|
||||
|
||||
- [(3.2)](#3.2)
|
||||
|
||||
an [*enum-head-name*](dcl.enum#nt:enum-head-name "9.8.1 Enumeration declarations [dcl.enum]"),
|
||||
|
||||
- [(3.3)](#3.3)
|
||||
|
||||
a [*qualified-id*](#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") that is the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") of a [*declarator-id*](dcl.decl.general#nt:declarator-id "9.3.1 General [dcl.decl.general]"), or
|
||||
|
||||
- [(3.4)](#3.4)
|
||||
|
||||
a declarative [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")[.](#3.sentence-1)
|
||||
|
||||
A declarative [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") shall not have a [*computed-type-specifier*](dcl.type.simple#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") or
|
||||
a [*splice-scope-specifier*](#nt:splice-scope-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")[.](#3.sentence-2)
|
||||
|
||||
A declaration that uses a declarative [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") shall be a friend declaration or
|
||||
inhabit a scope that contains the entity being redeclared or specialized[.](#3.sentence-3)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1890)
|
||||
|
||||
The entity designated by a [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") is determined as follows:
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
The [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") :: designates
|
||||
the global namespace[.](#4.1.sentence-1)
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
A [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") with a [*computed-type-specifier*](dcl.type.simple#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") designates the same type designated by the [*computed-type-specifier*](dcl.type.simple#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]"),
|
||||
which shall be a class or enumeration type[.](#4.2.sentence-1)
|
||||
|
||||
- [(4.3)](#4.3)
|
||||
|
||||
For a [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") of
|
||||
the form [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]") ::,
|
||||
the [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]") shall designate
|
||||
a class or enumeration type or a namespace[.](#4.3.sentence-1)
|
||||
The [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") designates the same entity
|
||||
as the [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]")[.](#4.3.sentence-2)
|
||||
|
||||
- [(4.4)](#4.4)
|
||||
|
||||
For a [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") of
|
||||
the formtemplateopt [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]") ::,
|
||||
the [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]") of
|
||||
the [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]") shall designate
|
||||
a class template or an alias template T[.](#4.4.sentence-1)
|
||||
Letting S be the specialization of T corresponding to the template argument list of
|
||||
the [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]"),S shall either be a class template specialization or
|
||||
an alias template specialization that denotes a class or enumeration type[.](#4.4.sentence-2)
|
||||
The [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") designates the underlying entity of S[.](#4.4.sentence-3)
|
||||
|
||||
- [(4.5)](#4.5)
|
||||
|
||||
If a [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") N is declarative and
|
||||
has a [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]") with a template argument list A that involves a template parameter,
|
||||
let T be the template nominated by N without A[.](#4.5.sentence-1)
|
||||
T shall be a class template[.](#4.5.sentence-2)
|
||||
|
||||
* [(4.5.1)](#4.5.1)
|
||||
|
||||
If A is the template argument list ([[temp.arg]](temp.arg "13.4 Template arguments")) of
|
||||
the corresponding [*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]") H ([[temp.mem]](temp.mem "13.7.3 Member templates")),N designates the primary template of T;H shall be equivalent to
|
||||
the [*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]") of T ([[temp.over.link]](temp.over.link "13.7.7.2 Function template overloading"))[.](#4.5.1.sentence-1)
|
||||
|
||||
* [(4.5.2)](#4.5.2)
|
||||
|
||||
Otherwise, N designates the partial specialization ([[temp.spec.partial]](temp.spec.partial "13.7.6 Partial specialization")) of T whose template argument list is equivalent to A ([[temp.over.link]](temp.over.link "13.7.7.2 Function template overloading"));
|
||||
the program is ill-formed if no such partial specialization exists[.](#4.5.2.sentence-1)
|
||||
|
||||
- [(4.6)](#4.6)
|
||||
|
||||
Any other [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") designates
|
||||
the entity denotes by its[*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]"),[*namespace-name*](namespace.def.general#nt:namespace-name "9.9.2.1 General [namespace.def.general]"),[*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]"), or[*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]")[.](#4.6.sentence-1)
|
||||
If the [*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") is not declarative,
|
||||
the entity shall not be a template[.](#4.6.sentence-2)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1951)
|
||||
|
||||
A [*qualified-id*](#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") shall not be of the form[*nested-name-specifier*](#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") templateopt ~[*computed-type-specifier*](dcl.type.simple#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") nor of the form[*computed-type-specifier*](dcl.type.simple#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") :: ~ [*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]")[.](#5.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1958)
|
||||
|
||||
The result of a [*qualified-id*](#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") Q is
|
||||
the entity it denotes ([[basic.lookup.qual]](basic.lookup.qual "6.5.5 Qualified name lookup"))[.](#6.sentence-1)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1962)
|
||||
|
||||
If Q appears
|
||||
in the predicate of a contract assertion C ([[basic.contract]](basic.contract "6.11 Contract assertions"))
|
||||
and the entity is
|
||||
|
||||
- [(7.1)](#7.1)
|
||||
|
||||
a variable
|
||||
declared outside of C of object type T,
|
||||
|
||||
- [(7.2)](#7.2)
|
||||
|
||||
a variable
|
||||
declared outside of C of type âreference to Tâ, or
|
||||
|
||||
- [(7.3)](#7.3)
|
||||
|
||||
a structured binding of type T whose corresponding variable
|
||||
is declared outside of C,
|
||||
|
||||
then the type of the expression is const T[.](#7.sentence-1)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1983)
|
||||
|
||||
Otherwise, the type of the expression is the type of the result[.](#8.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1986)
|
||||
|
||||
The result is an lvalue if the member is
|
||||
|
||||
- [(9.1)](#9.1)
|
||||
|
||||
a function other than a non-static member function,
|
||||
|
||||
- [(9.2)](#9.2)
|
||||
|
||||
a non-static member function
|
||||
if Q is the operand of a unary & operator,
|
||||
|
||||
- [(9.3)](#9.3)
|
||||
|
||||
a variable,
|
||||
|
||||
- [(9.4)](#9.4)
|
||||
|
||||
a structured binding ([[dcl.struct.bind]](dcl.struct.bind "9.7 Structured binding declarations")), or
|
||||
|
||||
- [(9.5)](#9.5)
|
||||
|
||||
a data member,
|
||||
|
||||
and a prvalue otherwise[.](#9.sentence-1)
|
||||
281
cppdraft/expr/prim/id/unqual.md
Normal file
281
cppdraft/expr/prim/id/unqual.md
Normal file
@@ -0,0 +1,281 @@
|
||||
[expr.prim.id.unqual]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#id.unqual)
|
||||
|
||||
### 7.5.5 Names [[expr.prim.id]](expr.prim.id#unqual)
|
||||
|
||||
#### 7.5.5.2 Unqualified names [expr.prim.id.unqual]
|
||||
|
||||
[unqualified-id:](#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]")
|
||||
[*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]")
|
||||
[*operator-function-id*](over.oper.general#nt:operator-function-id "12.4.1 General [over.oper.general]")
|
||||
[*conversion-function-id*](class.conv.fct#nt:conversion-function-id "11.4.8.3 Conversion functions [class.conv.fct]")
|
||||
[*literal-operator-id*](over.literal#nt:literal-operator-id "12.6 User-defined literals [over.literal]")
|
||||
~ [*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]")
|
||||
~ [*computed-type-specifier*](dcl.type.simple#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]")
|
||||
[*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]")
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1521)
|
||||
|
||||
An [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") is only
|
||||
an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") if it has
|
||||
been suitably declared ([[dcl]](dcl "9 Declarations"))
|
||||
or if it appears as part of a [*declarator-id*](dcl.decl.general#nt:declarator-id "9.3.1 General [dcl.decl.general]") ([[dcl.decl]](dcl.decl "9.3 Declarators"))[.](#1.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
For [*operator-function-id*](over.oper.general#nt:operator-function-id "12.4.1 General [over.oper.general]")*s*, see [[over.oper]](over.oper "12.4 Overloaded operators"); for[*conversion-function-id*](class.conv.fct#nt:conversion-function-id "11.4.8.3 Conversion functions [class.conv.fct]")*s*, see [[class.conv.fct]](class.conv.fct "11.4.8.3 Conversion functions"); for[*literal-operator-id*](over.literal#nt:literal-operator-id "12.6 User-defined literals [over.literal]")*s*, see [[over.literal]](over.literal "12.6 User-defined literals"); for[*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]")*s*, see [[temp.names]](temp.names "13.3 Names of template specializations")[.](#1.sentence-2)
|
||||
|
||||
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]") prefixed by ~ denotes the destructor of the type so named;
|
||||
see [[expr.prim.id.dtor]](expr.prim.id.dtor "7.5.5.5 Destruction")[.](#1.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1537)
|
||||
|
||||
A [*component name*](#def:component_name "7.5.5.2 Unqualified names [expr.prim.id.unqual]") of an [*unqualified-id*](#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]") U is
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
U if it is a name or
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
the component name of
|
||||
the [*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]") or [*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]") of U, if any[.](#2.sentence-1)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
Other constructs that contain names to look up can have several
|
||||
component names ([[expr.prim.id.qual]](expr.prim.id.qual "7.5.5.3 Qualified names"), [[dcl.type.simple]](dcl.type.simple "9.2.9.3 Simple type specifiers"), [[dcl.type.elab]](dcl.type.elab "9.2.9.5 Elaborated type specifiers"), [[dcl.mptr]](dcl.mptr "9.3.4.4 Pointers to members"), [[namespace.udecl]](namespace.udecl "9.10 The using declaration"), [[temp.param]](temp.param "13.2 Template parameters"), [[temp.names]](temp.names "13.3 Names of template specializations"), [[temp.res]](temp.res "13.8 Name resolution"))[.](#2.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
The [*terminal name*](#def:name,terminal "7.5.5.2 Unqualified names [expr.prim.id.unqual]") of a construct is
|
||||
the component name of that construct that appears lexically last[.](#2.sentence-3)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1554)
|
||||
|
||||
The result is the entity denoted by
|
||||
the [*unqualified-id*](#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]") ([[basic.lookup.unqual]](basic.lookup.unqual "6.5.3 Unqualified name lookup"))[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1558)
|
||||
|
||||
If
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
the [*unqualified-id*](#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]") appears in a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") at program point P,
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
the entity is a local entity ([[basic.pre]](basic.pre "6.1 Preamble"))
|
||||
or 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")),
|
||||
|
||||
- [(4.3)](#4.3)
|
||||
|
||||
naming the entity within the [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") of
|
||||
the innermost enclosing [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") of P,
|
||||
but not in an unevaluated operand, would refer to an entity captured by copy
|
||||
in some intervening [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]"), and
|
||||
|
||||
- [(4.4)](#4.4)
|
||||
|
||||
P is in the function parameter scope,
|
||||
but not the [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]"),
|
||||
of the innermost such [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") E,
|
||||
|
||||
then
|
||||
the type of the expression is
|
||||
the type of a class member access expression ([[expr.ref]](expr.ref "7.6.1.5 Class member access"))
|
||||
naming the non-static data member
|
||||
that would be declared for such a capture
|
||||
in the object parameter ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")) of the function call operator of E[.](#4.sentence-1)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
If E is not declared mutable,
|
||||
the type of such an identifier will typically be const qualified[.](#4.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1589)
|
||||
|
||||
Otherwise,
|
||||
if the [*unqualified-id*](#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]") names a coroutine parameter,
|
||||
the type of the expression is
|
||||
that of the copy of the parameter ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4 Coroutine definitions")),
|
||||
and the result is that copy[.](#5.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1597)
|
||||
|
||||
Otherwise,
|
||||
if the [*unqualified-id*](#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]") names a result binding ([[dcl.contract.res]](dcl.contract.res "9.4.2 Referring to the result object"))
|
||||
attached to a function *f* with return type U,
|
||||
|
||||
- [(6.1)](#6.1)
|
||||
|
||||
if U is âreference to Tâ,
|
||||
then the type of the expression isconst T;
|
||||
|
||||
- [(6.2)](#6.2)
|
||||
|
||||
otherwise,
|
||||
the type of the expression is const U[.](#6.sentence-1)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1613)
|
||||
|
||||
Otherwise,
|
||||
if the [*unqualified-id*](#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]") appears in the predicate of a contract assertion C ([[basic.contract]](basic.contract "6.11 Contract assertions"))
|
||||
and the entity is
|
||||
|
||||
- [(7.1)](#7.1)
|
||||
|
||||
a variable
|
||||
declared outside of C of object type T,
|
||||
|
||||
- [(7.2)](#7.2)
|
||||
|
||||
a variable or template parameter
|
||||
declared outside of C of type âreference to Tâ, or
|
||||
|
||||
- [(7.3)](#7.3)
|
||||
|
||||
a structured binding
|
||||
of type T whose corresponding variable
|
||||
is declared outside of C,
|
||||
|
||||
then the type of the expression is const T[.](#7.sentence-1)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1635)
|
||||
|
||||
[*Example [1](#example-1)*: int n = 0;struct X { bool m(); };
|
||||
|
||||
struct Y {int z = 0; void f(int i, int* p, int& r, X x, X* px) pre (++n) // error: attempting to modify const lvalue pre (++i) // error: attempting to modify const lvalue pre (++(*p)) // OK pre (++r) // error: attempting to modify const lvalue pre (x.m()) // error: calling non-const member function pre (px->m()) // OK pre ([=,&i,*this] mutable {++n; // error: attempting to modify const lvalue++i; // error: attempting to modify const lvalue++p; // OK, refers to member of closure type++r; // OK, refers to non-reference member of closure type++this->z; // OK, captured *this++z; // OK, captured *thisint j = 17; [&]{int k = 34; ++i; // error: attempting to modify const lvalue++j; // OK++k; // OK}(); return true; }()); template <int N, int& R, int* P>void g() pre(++N) // error: attempting to modify prvalue pre(++R) // error: attempting to modify const lvalue pre(++(*P)); // OKint h() post(r : ++r) // error: attempting to modify const lvalue post(r: [=] mutable {++r; // OK, refers to member of closure typereturn true; }()); int& k() post(r : ++r); // error: attempting to modify const lvalue}; â *end example*]
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1687)
|
||||
|
||||
Otherwise, if the entity is a template parameter object for
|
||||
a template parameter of type T ([[temp.param]](temp.param "13.2 Template parameters")),
|
||||
the type of the expression is const T[.](#9.sentence-1)
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1692)
|
||||
|
||||
In all other cases, the type of the expression is the type of the entity[.](#10.sentence-1)
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1695)
|
||||
|
||||
[*Note [4](#note-4)*:
|
||||
|
||||
The type will be adjusted as described in [[expr.type]](expr.type "7.2.2 Type") if it is cv-qualified or is a reference type[.](#11.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1701)
|
||||
|
||||
The expression is an xvalue if it is move-eligible (see below);
|
||||
an lvalue
|
||||
if the entity is a
|
||||
function,
|
||||
variable,
|
||||
structured binding ([[dcl.struct.bind]](dcl.struct.bind "9.7 Structured binding declarations")),
|
||||
result binding ([[dcl.contract.res]](dcl.contract.res "9.4.2 Referring to the result object")),
|
||||
data member, or
|
||||
template parameter object;
|
||||
and a prvalue otherwise ([[basic.lval]](basic.lval "7.2.1 Value category"));
|
||||
it is a bit-field if the identifier designates a bit-field[.](#12.sentence-1)
|
||||
|
||||
[13](#13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1714)
|
||||
|
||||
If an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") E appears in the predicate of
|
||||
a function contract assertion attached to a function *f* and denotes
|
||||
a function parameter of *f* and the implementation introduces any temporary objects
|
||||
to hold the value of that parameter as specified in [[class.temporary]](class.temporary "6.8.7 Temporary objects"),
|
||||
|
||||
- [(13.1)](#13.1)
|
||||
|
||||
if the contract assertion
|
||||
is a precondition assertion
|
||||
and the evaluation of the precondition assertion
|
||||
is sequenced before the initialization of the parameter object,E refers to the most recently initialized such temporary object, and
|
||||
|
||||
- [(13.2)](#13.2)
|
||||
|
||||
if the contract assertion
|
||||
is a postcondition assertion,
|
||||
it is unspecified whether E refers to
|
||||
one of the temporary objects or the parameter object;
|
||||
the choice is consistent within a single evaluation of a postcondition assertion[.](#13.sentence-1)
|
||||
|
||||
[14](#14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1737)
|
||||
|
||||
If an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") E names a result binding
|
||||
in a postcondition assertion
|
||||
and the implementation introduces any temporary objects
|
||||
to hold the result object as specified in [[class.temporary]](class.temporary "6.8.7 Temporary objects"),
|
||||
and the postcondition assertion
|
||||
is sequenced before the initialization of the result object ([[expr.call]](expr.call "7.6.1.3 Function call")),E refers to the most recently initialized such temporary object[.](#14.sentence-1)
|
||||
|
||||
[*Example [2](#example-2)*: void f() {float x, &r = x; [=]() -> decltype((x)) { // lambda returns float const& because this lambda is not mutable and// x is an lvaluedecltype(x) y1; // y1 has type floatdecltype((x)) y2 = y1; // y2 has type float const&decltype(r) r1 = y1; // r1 has type float&decltype((r)) r2 = y2; // r2 has type float const&return y2; }; [=](decltype((x)) y) {decltype((x)) z = x; // OK, y has type float&, z has type float const&}; [=] {[](decltype((x)) y) {}; // OK, lambda takes a parameter of type float const&[x=1](decltype((x)) y) {decltype((x)) z = x; // OK, y has type int&, z has type int const&}; };} â *end example*]
|
||||
|
||||
[15](#15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1777)
|
||||
|
||||
An [*implicitly movable entity*](#def:entity,implicitly_movable "7.5.5.2 Unqualified names [expr.prim.id.unqual]") is
|
||||
a variable with automatic storage duration
|
||||
that is either a non-volatile object or
|
||||
an rvalue reference to a non-volatile object type[.](#15.sentence-1)
|
||||
|
||||
An [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") or[*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") ([[expr.prim.splice]](expr.prim.splice "7.5.9 Expression splicing"))
|
||||
is [*move-eligible*](#def:move-eligible "7.5.5.2 Unqualified names [expr.prim.id.unqual]") if
|
||||
|
||||
- [(15.1)](#15.1)
|
||||
|
||||
it designates an implicitly movable entity,
|
||||
|
||||
- [(15.2)](#15.2)
|
||||
|
||||
it is the (possibly parenthesized)
|
||||
operand of a return ([[stmt.return]](stmt.return "8.8.4 The return statement")) orco_return ([[stmt.return.coroutine]](stmt.return.coroutine "8.8.5 The co_return statement")) statement or
|
||||
of a [*throw-expression*](expr.throw#nt:throw-expression "7.6.18 Throwing an exception [expr.throw]") ([[expr.throw]](expr.throw "7.6.18 Throwing an exception")), and
|
||||
|
||||
- [(15.3)](#15.3)
|
||||
|
||||
each intervening scope between
|
||||
the declaration of the entity and
|
||||
the innermost enclosing scope of the expression
|
||||
is a block scope and,
|
||||
for a [*throw-expression*](expr.throw#nt:throw-expression "7.6.18 Throwing an exception [expr.throw]"),
|
||||
is not the block scope of
|
||||
a [*try-block*](except.pre#nt:try-block "14.1 Preamble [except.pre]") or [*function-try-block*](except.pre#nt:function-try-block "14.1 Preamble [except.pre]")[.](#15.sentence-2)
|
||||
905
cppdraft/expr/prim/lambda.md
Normal file
905
cppdraft/expr/prim/lambda.md
Normal file
@@ -0,0 +1,905 @@
|
||||
[expr.prim.lambda]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#lambda)
|
||||
|
||||
### 7.5.6 Lambda expressions [expr.prim.lambda]
|
||||
|
||||
#### [7.5.6.1](#general) General [[expr.prim.lambda.general]](expr.prim.lambda.general)
|
||||
|
||||
[lambda-expression:](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")
|
||||
[*lambda-introducer*](#nt:lambda-introducer "7.5.6.1 General [expr.prim.lambda.general]") [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt [*lambda-declarator*](#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]") [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]")
|
||||
[*lambda-introducer*](#nt:lambda-introducer "7.5.6.1 General [expr.prim.lambda.general]") < [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]") > [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]")opt [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt
|
||||
[*lambda-declarator*](#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]") [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]")
|
||||
|
||||
[lambda-introducer:](#nt:lambda-introducer "7.5.6.1 General [expr.prim.lambda.general]")
|
||||
[ [*lambda-capture*](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")opt ]
|
||||
|
||||
[lambda-declarator:](#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]")
|
||||
[*lambda-specifier-seq*](#nt:lambda-specifier-seq "7.5.6.1 General [expr.prim.lambda.general]") [*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5 Exception specifications [except.spec]")opt [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]")opt
|
||||
[*function-contract-specifier-seq*](dcl.contract.func#nt:function-contract-specifier-seq "9.4.1 General [dcl.contract.func]")opt
|
||||
[*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5 Exception specifications [except.spec]") [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]")opt [*function-contract-specifier-seq*](dcl.contract.func#nt:function-contract-specifier-seq "9.4.1 General [dcl.contract.func]")opt
|
||||
[*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]")opt [*function-contract-specifier-seq*](dcl.contract.func#nt:function-contract-specifier-seq "9.4.1 General [dcl.contract.func]")opt
|
||||
( [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") ) [*lambda-specifier-seq*](#nt:lambda-specifier-seq "7.5.6.1 General [expr.prim.lambda.general]")opt [*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5 Exception specifications [except.spec]")opt [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt
|
||||
[*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]")opt [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]")opt [*function-contract-specifier-seq*](dcl.contract.func#nt:function-contract-specifier-seq "9.4.1 General [dcl.contract.func]")opt
|
||||
|
||||
[lambda-specifier:](#nt:lambda-specifier "7.5.6.1 General [expr.prim.lambda.general]")
|
||||
consteval
|
||||
constexpr
|
||||
mutable
|
||||
static
|
||||
|
||||
[lambda-specifier-seq:](#nt:lambda-specifier-seq "7.5.6.1 General [expr.prim.lambda.general]")
|
||||
[*lambda-specifier*](#nt:lambda-specifier "7.5.6.1 General [expr.prim.lambda.general]") [*lambda-specifier-seq*](#nt:lambda-specifier-seq "7.5.6.1 General [expr.prim.lambda.general]")opt
|
||||
|
||||
[1](#general-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2106)
|
||||
|
||||
A [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") provides
|
||||
a concise way to create a simple function object[.](#general-1.sentence-1)
|
||||
|
||||
[*Example [1](#general-example-1)*: #include <algorithm>#include <cmath>void abssort(float* x, unsigned N) { std::sort(x, x + N, [](float a, float b) { return std::abs(a) < std::abs(b); });} â *end example*]
|
||||
|
||||
[2](#general-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2119)
|
||||
|
||||
A [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") is a prvalue
|
||||
whose result object is called the [*closure object*](#def:closure_object "7.5.6.1 General [expr.prim.lambda.general]")[.](#general-2.sentence-1)
|
||||
|
||||
[*Note [1](#general-note-1)*:
|
||||
|
||||
A closure object behaves like a [function
|
||||
object](function.objects "22.10 Function objects [function.objects]")[.](#general-2.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#general-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2127)
|
||||
|
||||
An ambiguity can arise
|
||||
because a [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") can end in
|
||||
an [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]"),
|
||||
which collides with
|
||||
the [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") in [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")[.](#general-3.sentence-1)
|
||||
|
||||
In such cases,
|
||||
any attributes are treated as[*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") in [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")[.](#general-3.sentence-2)
|
||||
|
||||
[*Note [2](#general-note-2)*:
|
||||
|
||||
Such ambiguous cases cannot have valid semantics
|
||||
because the constraint expression would not have type bool[.](#general-3.sentence-3)
|
||||
|
||||
[*Example [2](#general-example-2)*: auto x = []<class T> requires T::operator int [[some_attribute]] (int) { } â *end example*]
|
||||
|
||||
â *end note*]
|
||||
|
||||
[4](#general-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2146)
|
||||
|
||||
A [*lambda-specifier-seq*](#nt:lambda-specifier-seq "7.5.6.1 General [expr.prim.lambda.general]") shall contain at most one of each [*lambda-specifier*](#nt:lambda-specifier "7.5.6.1 General [expr.prim.lambda.general]") and
|
||||
shall not contain both constexpr and consteval[.](#general-4.sentence-1)
|
||||
|
||||
If the [*lambda-declarator*](#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]") contains
|
||||
an explicit object parameter ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")),
|
||||
then no [*lambda-specifier*](#nt:lambda-specifier "7.5.6.1 General [expr.prim.lambda.general]") in the [*lambda-specifier-seq*](#nt:lambda-specifier-seq "7.5.6.1 General [expr.prim.lambda.general]") shall be mutable or static[.](#general-4.sentence-2)
|
||||
|
||||
The [*lambda-specifier-seq*](#nt:lambda-specifier-seq "7.5.6.1 General [expr.prim.lambda.general]") shall not contain
|
||||
both mutable and static[.](#general-4.sentence-3)
|
||||
|
||||
If the [*lambda-specifier-seq*](#nt:lambda-specifier-seq "7.5.6.1 General [expr.prim.lambda.general]") contains static,
|
||||
there shall be no [*lambda-capture*](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")[.](#general-4.sentence-4)
|
||||
|
||||
[*Note [3](#general-note-3)*:
|
||||
|
||||
The trailing [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") is described in [[dcl.decl]](dcl.decl "9.3 Declarators")[.](#general-4.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#general-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2162)
|
||||
|
||||
A [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")'s [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") is the [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") of
|
||||
the [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")'s [*lambda-declarator*](#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]"), if any,
|
||||
or empty otherwise[.](#general-5.sentence-1)
|
||||
|
||||
If the [*lambda-declarator*](#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]") does not include a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]"),
|
||||
it is considered to be -> auto[.](#general-5.sentence-2)
|
||||
|
||||
[*Note [4](#general-note-4)*:
|
||||
|
||||
In that case, the return type is deduced from return statements
|
||||
as described in [[dcl.spec.auto]](dcl.spec.auto "9.2.9.7 Placeholder type specifiers")[.](#general-5.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [3](#general-example-3)*: auto x1 = [](int i) { return i; }; // OK, return type is intauto x2 = []{ return { 1, 2 }; }; // error: deducing return type from [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]")int j;auto x3 = [&]()->auto&& { return j; }; // OK, return type is int& â *end example*]
|
||||
|
||||
[6](#general-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2183)
|
||||
|
||||
A lambda is a [*generic lambda*](#def:generic_lambda "7.5.6.1 General [expr.prim.lambda.general]") if the [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") has any generic parameter type placeholders ([[dcl.spec.auto]](dcl.spec.auto "9.2.9.7 Placeholder type specifiers")), or
|
||||
if the lambda has a [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]")[.](#general-6.sentence-1)
|
||||
|
||||
[*Example [4](#general-example-4)*: auto x = [](int i, auto a) { return i; }; // OK, a generic lambdaauto y = [](this auto self, int i) { return i; }; // OK, a generic lambdaauto z = []<class T>(int i) { return i; }; // OK, a generic lambda â *end example*]
|
||||
|
||||
#### [7.5.6.2](#closure) Closure types [[expr.prim.lambda.closure]](expr.prim.lambda.closure)
|
||||
|
||||
[1](#closure-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2198)
|
||||
|
||||
The type of a [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") (which is also the type of the
|
||||
closure object) is a unique, unnamed non-union class type,
|
||||
called the [*closure type*](#def:closure_type "7.5.6.2 Closure types [expr.prim.lambda.closure]"),
|
||||
whose properties are described below[.](#closure-1.sentence-1)
|
||||
|
||||
[2](#closure-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2204)
|
||||
|
||||
The closure type is not complete
|
||||
until the end of its corresponding [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]")[.](#closure-2.sentence-1)
|
||||
|
||||
[3](#closure-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2208)
|
||||
|
||||
The closure type is declared in the smallest block
|
||||
scope, class scope, or namespace scope that contains the corresponding[*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")[.](#closure-3.sentence-1)
|
||||
|
||||
[*Note [1](#closure-note-1)*:
|
||||
|
||||
This determines the set of namespaces and
|
||||
classes associated with the closure type ([[basic.lookup.argdep]](basic.lookup.argdep "6.5.4 Argument-dependent name lookup"))[.](#closure-3.sentence-2)
|
||||
|
||||
The parameter
|
||||
types of a [*lambda-declarator*](#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]") do not affect these associated namespaces and
|
||||
classes[.](#closure-3.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[4](#closure-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2219)
|
||||
|
||||
The closure type is not an aggregate type ([[dcl.init.aggr]](dcl.init.aggr "9.5.2 Aggregates"));
|
||||
it is a structural type ([[temp.param]](temp.param#term.structural.type "13.2 Template parameters")) if and only if
|
||||
the lambda has no [*lambda-capture*](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")[.](#closure-4.sentence-1)
|
||||
|
||||
An implementation may define the closure type differently from what
|
||||
is described below provided this does not alter the observable behavior of the program
|
||||
other than by changing:
|
||||
|
||||
- [(4.1)](#closure-4.1)
|
||||
|
||||
the size and/or alignment of the closure type,
|
||||
|
||||
- [(4.2)](#closure-4.2)
|
||||
|
||||
whether the closure type is trivially copyable ([[class.prop]](class.prop "11.2 Properties of classes")),
|
||||
|
||||
- [(4.3)](#closure-4.3)
|
||||
|
||||
whether the closure type is trivially relocatable ([[class.prop]](class.prop "11.2 Properties of classes")),
|
||||
|
||||
- [(4.4)](#closure-4.4)
|
||||
|
||||
whether the closure type is replaceable ([[class.prop]](class.prop "11.2 Properties of classes")), or
|
||||
|
||||
- [(4.5)](#closure-4.5)
|
||||
|
||||
whether the closure type is a standard-layout class ([[class.prop]](class.prop "11.2 Properties of classes"))[.](#closure-4.sentence-2)
|
||||
|
||||
An implementation shall not add members of rvalue reference type to the closure
|
||||
type[.](#closure-4.sentence-3)
|
||||
|
||||
[5](#closure-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2237)
|
||||
|
||||
The closure type for a [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") has a public
|
||||
inline function call operator (for a non-generic lambda) or
|
||||
function call operator template (for a generic lambda) ([[over.call]](over.call "12.4.4 Function call"))
|
||||
whose parameters and return type
|
||||
are those of the [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")'s[*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") and [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]") respectively, and whose[*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]") consists of
|
||||
the specified [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]"), if any[.](#closure-5.sentence-1)
|
||||
|
||||
The function call operator or the function call operator template are
|
||||
direct members of the closure type[.](#closure-5.sentence-2)
|
||||
|
||||
The [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") of the function call operator template
|
||||
is the [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") immediately following< [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]") >, if any[.](#closure-5.sentence-3)
|
||||
|
||||
The trailing [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") of the function call operator
|
||||
or operator template is the [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") of the [*lambda-declarator*](#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]"), if any[.](#closure-5.sentence-4)
|
||||
|
||||
[*Note [2](#closure-note-2)*:
|
||||
|
||||
The function call operator template for a generic lambda can be
|
||||
an abbreviated function template ([[dcl.fct]](dcl.fct "9.3.4.6 Functions"))[.](#closure-5.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [1](#closure-example-1)*: auto glambda = [](auto a, auto&& b) { return a < b; };bool b = glambda(3, 3.14); // OKauto vglambda = [](auto printer) {return [=](auto&& ... ts) { // OK, ts is a function parameter pack printer(std::forward<decltype(ts)>(ts)...); return [=]() { printer(ts ...); }; };};auto p = vglambda( [](auto v1, auto v2, auto v3){ std::cout << v1 << v2 << v3; } );auto q = p(1, 'a', 3.14); // OK, outputs 1a3.14 q(); // OK, outputs 1a3.14auto fact = [](this auto self, int n) -> int { // OK, explicit object parameterreturn (n <= 1) ? 1 : n * self(n-1);};
|
||||
std::cout << fact(5); // OK, outputs 120 â *end example*]
|
||||
|
||||
[6](#closure-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2285)
|
||||
|
||||
Given a lambda with a [*lambda-capture*](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]"),
|
||||
the type of the explicit object parameter, if any,
|
||||
of the lambda's function call operator
|
||||
(possibly instantiated from a function call operator template)
|
||||
shall be either:
|
||||
|
||||
- [(6.1)](#closure-6.1)
|
||||
|
||||
the closure type,
|
||||
|
||||
- [(6.2)](#closure-6.2)
|
||||
|
||||
a class type publicly and unambiguously derived from the closure type, or
|
||||
|
||||
- [(6.3)](#closure-6.3)
|
||||
|
||||
a reference to a possibly cv-qualified such type[.](#closure-6.sentence-1)
|
||||
|
||||
[*Example [2](#closure-example-2)*: struct C {template <typename T> C(T);};
|
||||
|
||||
void func(int i) {int x = [=](this auto&&) { return i; }(); // OKint y = [=](this C) { return i; }(); // errorint z = [](this C) { return 42; }(); // OK} â *end example*]
|
||||
|
||||
[7](#closure-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2314)
|
||||
|
||||
The function call operator or operator template is
|
||||
a static member function or static member function template ([[class.static.mfct]](class.static.mfct "11.4.9.2 Static member functions"))
|
||||
if the [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")'s[*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") is followed by static[.](#closure-7.sentence-1)
|
||||
|
||||
Otherwise, it is
|
||||
a non-static member function or member function template ([[class.mfct.non.static]](class.mfct.non.static "11.4.3 Non-static member functions"))
|
||||
that is declaredconst ([[class.mfct.non.static]](class.mfct.non.static "11.4.3 Non-static member functions")) if and only if the[*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")'s [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") is not
|
||||
followed by mutable and
|
||||
the [*lambda-declarator*](#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]") does not contain
|
||||
an explicit object parameter[.](#closure-7.sentence-2)
|
||||
|
||||
It is neither virtual nor declared volatile[.](#closure-7.sentence-3)
|
||||
|
||||
Any [*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5 Exception specifications [except.spec]") or [*function-contract-specifier*](dcl.contract.func#nt:function-contract-specifier "9.4.1 General [dcl.contract.func]") ([[dcl.contract.func]](dcl.contract.func "9.4.1 General"))
|
||||
specified on a [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") applies to the corresponding function call operator or operator template[.](#closure-7.sentence-4)
|
||||
|
||||
An [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") in a [*lambda-declarator*](#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]") appertains
|
||||
to the type of the corresponding function call operator or operator template[.](#closure-7.sentence-5)
|
||||
|
||||
An [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") in a [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") preceding a [*lambda-declarator*](#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]") appertains to the corresponding function call operator or operator template[.](#closure-7.sentence-6)
|
||||
|
||||
The function call operator or any given operator template specialization
|
||||
is a constexpr function if either
|
||||
the corresponding [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")'s[*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") is followed by constexpr or consteval, or
|
||||
it is constexpr-suitable ([[dcl.constexpr]](dcl.constexpr "9.2.6 The constexpr and consteval specifiers"))[.](#closure-7.sentence-7)
|
||||
|
||||
It is an immediate function ([[dcl.constexpr]](dcl.constexpr "9.2.6 The constexpr and consteval specifiers"))
|
||||
if the corresponding [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")'s[*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") is followed by consteval[.](#closure-7.sentence-8)
|
||||
|
||||
[*Example [3](#closure-example-3)*: auto ID = [](auto a) { return a; };static_assert(ID(3) == 3); // OKstruct NonLiteral { NonLiteral(int n) : n(n) { }int n;};static_assert(ID(NonLiteral{3}).n == 3); // error â *end example*]
|
||||
|
||||
[8](#closure-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2358)
|
||||
|
||||
[*Example [4](#closure-example-4)*: auto monoid = [](auto v) { return [=] { return v; }; };auto add = [](auto m1) constexpr {auto ret = m1(); return [=](auto m2) mutable {auto m1val = m1(); auto plus = [=](auto m2val) mutable constexpr{ return m1val += m2val; };
|
||||
ret = plus(m2()); return monoid(ret); };};constexpr auto zero = monoid(0);constexpr auto one = monoid(1);static_assert(add(one)(zero)() == one()); // OK// Since two below is not declared constexpr, an evaluation of its constexpr member function call operator// cannot perform an lvalue-to-rvalue conversion on one of its subobjects (that represents its capture)// in a constant expression.auto two = monoid(2);
|
||||
assert(two() == 2); // OK, not a constant expression.static_assert(add(one)(one)() == two()); // error: two() is not a constant expressionstatic_assert(add(one)(one)() == monoid(2)()); // OK â *end example*]
|
||||
|
||||
[9](#closure-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2386)
|
||||
|
||||
[*Note [3](#closure-note-3)*:
|
||||
|
||||
The function call operator or operator template can be constrained ([[temp.constr.decl]](temp.constr.decl "13.5.3 Constrained declarations"))
|
||||
by a [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]") ([[temp.param]](temp.param "13.2 Template parameters")),
|
||||
a [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") ([[temp.pre]](temp.pre "13.1 Preamble")),
|
||||
or a trailing [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") ([[dcl.decl]](dcl.decl "9.3 Declarators"))[.](#closure-9.sentence-1)
|
||||
|
||||
[*Example [5](#closure-example-5)*: template <typename T> concept C1 = /* ... */;template <std::size_t N> concept C2 = /* ... */;template <typename A, typename B> concept C3 = /* ... */;
|
||||
|
||||
auto f = []<typename T1, C1 T2> requires C2<sizeof(T1) + sizeof(T2)>(T1 a1, T1 b1, T2 a2, auto a3, auto a4) requires C3<decltype(a4), T2> {// T2 is constrained by a [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]").// T1 and T2 are constrained by a [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]"), and// T2 and the type of a4 are constrained by a trailing [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]").}; â *end example*]
|
||||
|
||||
â *end note*]
|
||||
|
||||
[10](#closure-10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2408)
|
||||
|
||||
If all potential references
|
||||
to a local entity implicitly captured by a [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") L occur within the function contract assertions ([[dcl.contract.func]](dcl.contract.func "9.4.1 General"))
|
||||
of the call operator or operator template of L or within [*assertion-statement*](stmt.contract.assert#nt:assertion-statement "8.9 Assertion statement [stmt.contract.assert]")*s* ([[stmt.contract.assert]](stmt.contract.assert "8.9 Assertion statement"))
|
||||
within the body of L,
|
||||
the program is ill-formed[.](#closure-10.sentence-1)
|
||||
|
||||
[*Note [4](#closure-note-4)*:
|
||||
|
||||
Adding a contract assertion to an existing C++ program cannot
|
||||
cause additional captures[.](#closure-10.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [6](#closure-example-6)*: static int i = 0;
|
||||
|
||||
void test() {auto f1 = [=] pre(i > 0) {}; // OK, no local entities are captured.int i = 1; auto f2 = [=] pre(i > 0) {}; // error: cannot implicitly capture i hereauto f3 = [i] pre(i > 0) {}; // OK, i is captured explicitly.auto f4 = [=] {contract_assert(i > 0); // error: cannot implicitly capture i here}; auto f5 = [=] {contract_assert(i > 0); // OK, i is referenced elsewhere.(void)i; }; auto f6 = [=] pre( // #1[]{bool x = true; return [=]{ return x; }(); // OK, #1 captures nothing.}()) {}; bool y = true; auto f7 = [=] pre([=]{ return y; }()); // error: outer capture of y is invalid.} â *end example*]
|
||||
|
||||
[11](#closure-11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2453)
|
||||
|
||||
The closure type for a non-generic [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") with no[*lambda-capture*](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") and no explicit object parameter ([[dcl.fct]](dcl.fct "9.3.4.6 Functions"))
|
||||
whose constraints (if any) are satisfied
|
||||
has a conversion function to pointer to
|
||||
function with C++ language [linkage](dcl.link "9.12 Linkage specifications [dcl.link]") having
|
||||
the same parameter and return types as the closure type's function call operator[.](#closure-11.sentence-1)
|
||||
|
||||
The conversion is to âpointer to noexcept functionâ
|
||||
if the function call operator
|
||||
has a non-throwing exception specification[.](#closure-11.sentence-2)
|
||||
|
||||
If the function call operator is a static member function,
|
||||
then the value returned by this conversion function is
|
||||
a pointer to the function call operator[.](#closure-11.sentence-3)
|
||||
|
||||
Otherwise, the value returned by this conversion function
|
||||
is a pointer to a function F that, when invoked,
|
||||
has the same effect as invoking the closure type's function call operator
|
||||
on a default-constructed instance of the closure type[.](#closure-11.sentence-4)
|
||||
|
||||
F is a constexpr function
|
||||
if the function call operator is a constexpr function
|
||||
and is an immediate function
|
||||
if the function call operator is an immediate function[.](#closure-11.sentence-5)
|
||||
|
||||
[12](#closure-12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2476)
|
||||
|
||||
For a generic lambda with no [*lambda-capture*](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") and no explicit object parameter ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")),
|
||||
the closure type has a
|
||||
conversion function template to
|
||||
pointer to function[.](#closure-12.sentence-1)
|
||||
|
||||
The conversion function template has the same invented
|
||||
template parameter list, and the pointer to function has the same
|
||||
parameter types, as the function call operator template[.](#closure-12.sentence-2)
|
||||
|
||||
The return type of
|
||||
the pointer to function shall behave as if it were a[*decltype-specifier*](dcl.type.decltype#nt:decltype-specifier "9.2.9.6 Decltype specifiers [dcl.type.decltype]") denoting the return type of the corresponding
|
||||
function call operator template specialization[.](#closure-12.sentence-3)
|
||||
|
||||
[13](#closure-13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2488)
|
||||
|
||||
[*Note [5](#closure-note-5)*:
|
||||
|
||||
If the generic lambda has no [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]") or
|
||||
the [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]") contains a placeholder type, return type
|
||||
deduction of the corresponding function call operator template specialization
|
||||
has to be done[.](#closure-13.sentence-1)
|
||||
|
||||
The corresponding specialization is that instantiation of the
|
||||
function call operator template with the same template arguments as those
|
||||
deduced for the conversion function template[.](#closure-13.sentence-2)
|
||||
|
||||
Consider the following:auto glambda = [](auto a) { return a; };int (*fp)(int) = glambda;
|
||||
|
||||
The behavior of the conversion function of glambda above is like
|
||||
that of the following conversion function:struct Closure {template<class T> auto operator()(T t) const { /* ... */ }template<class T> static auto lambda_call_operator_invoker(T a) {// forwards execution to operator()(a) and therefore has// the same return type deduced/* ... */}template<class T> using fptr_t =decltype(lambda_call_operator_invoker(declval<T>())) (*)(T); template<class T> operator fptr_t<T>() const{ return &lambda_call_operator_invoker; }};
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [7](#closure-example-7)*: void f1(int (*)(int)) { }void f2(char (*)(int)) { }void g(int (*)(int)) { } // #1void g(char (*)(char)) { } // #2void h(int (*)(int)) { } // #3void h(char (*)(int)) { } // #4auto glambda = [](auto a) { return a; };
|
||||
f1(glambda); // OK f2(glambda); // error: ID is not convertible g(glambda); // error: ambiguous h(glambda); // OK, calls #3 since it is convertible from IDint& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK â *end example*]
|
||||
|
||||
[14](#closure-14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2539)
|
||||
|
||||
If the function call operator template is a static member function template,
|
||||
then the value returned by
|
||||
any given specialization of this conversion function template is
|
||||
a pointer to the corresponding function call operator template specialization[.](#closure-14.sentence-1)
|
||||
|
||||
Otherwise,
|
||||
the value returned by any given specialization of this conversion function
|
||||
template is a pointer to a function F that, when invoked, has the same
|
||||
effect as invoking the generic lambda's corresponding function call operator
|
||||
template specialization on a default-constructed instance of the closure type[.](#closure-14.sentence-2)
|
||||
|
||||
F is a constexpr function
|
||||
if the corresponding specialization is a constexpr function andF is an immediate function
|
||||
if the function call operator template specialization is an immediate function[.](#closure-14.sentence-3)
|
||||
|
||||
[*Note [6](#closure-note-6)*:
|
||||
|
||||
This will result in the implicit instantiation of the generic lambda's body[.](#closure-14.sentence-4)
|
||||
|
||||
The instantiated generic lambda's return type and parameter types need to match
|
||||
the return type and parameter types of the pointer to function[.](#closure-14.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [8](#closure-example-8)*: auto GL = [](auto a) { std::cout << a; return a; };int (*GL_int)(int) = GL; // OK, through conversion function template GL_int(3); // OK, same as GL(3) â *end example*]
|
||||
|
||||
[15](#closure-15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2566)
|
||||
|
||||
The conversion function or conversion function template is public,
|
||||
constexpr, non-virtual, non-explicit, const, and has a non-throwing [exception
|
||||
specification](except.spec "14.5 Exception specifications [except.spec]")[.](#closure-15.sentence-1)
|
||||
|
||||
[*Example [9](#closure-example-9)*: auto Fwd = [](int (*fp)(int), auto a) { return fp(a); };auto C = [](auto a) { return a; };
|
||||
|
||||
static_assert(Fwd(C,3) == 3); // OK// No specialization of the function call operator template can be constexpr (due to the local static).auto NC = [](auto a) { static int s; return a; };static_assert(Fwd(NC,3) == 3); // error â *end example*]
|
||||
|
||||
[16](#closure-16)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2583)
|
||||
|
||||
The [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")'s [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") yields
|
||||
the [*function-body*](dcl.fct.def.general#nt:function-body "9.6.1 General [dcl.fct.def.general]") ([[dcl.fct.def]](dcl.fct.def "9.6 Function definitions")) of the function call operator,
|
||||
but it is not within the scope of the closure type[.](#closure-16.sentence-1)
|
||||
|
||||
[*Example [10](#closure-example-10)*: struct S1 {int x, y; int operator()(int); void f() {[=]()->int {return operator()(this->x + y); // equivalent to S1::operator()(this->x + (*this).y)// this has type S1*}; }}; â *end example*]
|
||||
|
||||
Unless the [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") is
|
||||
that of a [*consteval-block-declaration*](dcl.pre#nt:consteval-block-declaration "9.1 Preamble [dcl.pre]") ([[dcl.pre]](dcl.pre "9.1 Preamble")),
|
||||
a variable __func__ is implicitly defined at the beginning of
|
||||
the [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") of the [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]"),
|
||||
with semantics as described in [[dcl.fct.def.general]](dcl.fct.def.general "9.6.1 General")[.](#closure-16.sentence-2)
|
||||
|
||||
[17](#closure-17)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2607)
|
||||
|
||||
The closure type associated with a [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") has no
|
||||
default constructor
|
||||
if the [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") has a [*lambda-capture*](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") and a defaulted default constructor otherwise[.](#closure-17.sentence-1)
|
||||
|
||||
It has a defaulted copy constructor and a defaulted move constructor ([[class.copy.ctor]](class.copy.ctor "11.4.5.3 Copy/move constructors"))[.](#closure-17.sentence-2)
|
||||
|
||||
It has a deleted copy assignment operator if the [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") has a [*lambda-capture*](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") and defaulted copy and move assignment
|
||||
operators otherwise ([[class.copy.assign]](class.copy.assign "11.4.6 Copy/move assignment operator"))[.](#closure-17.sentence-3)
|
||||
|
||||
[*Note [7](#closure-note-7)*:
|
||||
|
||||
These special member functions are implicitly defined as
|
||||
usual, which can result in them being defined as deleted[.](#closure-17.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[18](#closure-18)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2621)
|
||||
|
||||
The closure type associated with a [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") has an
|
||||
implicitly-declared destructor ([[class.dtor]](class.dtor "11.4.7 Destructors"))[.](#closure-18.sentence-1)
|
||||
|
||||
[19](#closure-19)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2625)
|
||||
|
||||
A member of a closure type shall not be[explicitly instantiated](temp.explicit "13.9.3 Explicit instantiation [temp.explicit]"),[explicitly specialized](temp.expl.spec "13.9.4 Explicit specialization [temp.expl.spec]"), or
|
||||
named in a [friend declaration](class.friend "11.8.4 Friends [class.friend]")[.](#closure-19.sentence-1)
|
||||
|
||||
#### [7.5.6.3](#capture) Captures [[expr.prim.lambda.capture]](expr.prim.lambda.capture)
|
||||
|
||||
[lambda-capture:](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
[*capture-default*](#nt:capture-default "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
[*capture-list*](#nt:capture-list "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
[*capture-default*](#nt:capture-default "7.5.6.3 Captures [expr.prim.lambda.capture]") , [*capture-list*](#nt:capture-list "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
|
||||
[capture-default:](#nt:capture-default "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
&
|
||||
=
|
||||
|
||||
[capture-list:](#nt:capture-list "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
[*capture*](#nt:capture "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
[*capture-list*](#nt:capture-list "7.5.6.3 Captures [expr.prim.lambda.capture]") , [*capture*](#nt:capture "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
|
||||
[capture:](#nt:capture "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
[*simple-capture*](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
[*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
|
||||
[simple-capture:](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
[*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") ...opt
|
||||
& [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") ...opt
|
||||
this
|
||||
* this
|
||||
|
||||
[init-capture:](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
...opt [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]")
|
||||
& ...opt [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]")
|
||||
|
||||
[1](#capture-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2672)
|
||||
|
||||
The body of a [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") may refer to local entities
|
||||
of enclosing scopes by capturing those entities, as described
|
||||
below[.](#capture-1.sentence-1)
|
||||
|
||||
[2](#capture-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2677)
|
||||
|
||||
If a [*lambda-capture*](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") includes a [*capture-default*](#nt:capture-default "7.5.6.3 Captures [expr.prim.lambda.capture]") that
|
||||
is &, no identifier in a [*simple-capture*](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") of that[*lambda-capture*](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") shall be preceded
|
||||
by &[.](#capture-2.sentence-1)
|
||||
|
||||
If a [*lambda-capture*](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") includes a[*capture-default*](#nt:capture-default "7.5.6.3 Captures [expr.prim.lambda.capture]") that is =, each[*simple-capture*](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") of that [*lambda-capture*](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") shall
|
||||
be of the form
|
||||
â& [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") ...optâ,
|
||||
âthisâ,
|
||||
or â* thisâ[.](#capture-2.sentence-2)
|
||||
|
||||
[*Note [1](#capture-note-1)*:
|
||||
|
||||
The form [&,this] is redundant but accepted
|
||||
for compatibility with C++ 2014[.](#capture-2.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
Ignoring appearances in[*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]")*s* of [*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")*s*, an identifier orthis shall not appear more than once in a[*lambda-capture*](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")[.](#capture-2.sentence-4)
|
||||
|
||||
[*Example [1](#capture-example-1)*: struct S2 { void f(int i); };void S2::f(int i) {[&, i]{ }; // OK[&, this, i]{ }; // OK, equivalent to [&, i][&, &i]{ }; // error: i preceded by & when & is the default[=, *this]{ }; // OK[=, this]{ }; // OK, equivalent to [=][i, i]{ }; // error: i repeated[this, *this]{ }; // error: this appears twice} â *end example*]
|
||||
|
||||
[3](#capture-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2711)
|
||||
|
||||
A [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") shall not have
|
||||
a [*capture-default*](#nt:capture-default "7.5.6.3 Captures [expr.prim.lambda.capture]") or [*simple-capture*](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") in its [*lambda-introducer*](#nt:lambda-introducer "7.5.6.1 General [expr.prim.lambda.general]") unless
|
||||
|
||||
- [(3.1)](#capture-3.1)
|
||||
|
||||
its innermost enclosing scope is a block scope ([[basic.scope.block]](basic.scope.block "6.4.3 Block scope")),
|
||||
|
||||
- [(3.2)](#capture-3.2)
|
||||
|
||||
it appears within a default member initializer
|
||||
and its innermost enclosing scope is
|
||||
the corresponding class scope ([[basic.scope.class]](basic.scope.class "6.4.7 Class scope")), or
|
||||
|
||||
- [(3.3)](#capture-3.3)
|
||||
|
||||
it appears within a contract assertion
|
||||
and its innermost enclosing scope
|
||||
is the corresponding contract-assertion scope ([[basic.scope.contract]](basic.scope.contract "6.4.10 Contract-assertion scope"))[.](#capture-3.sentence-1)
|
||||
|
||||
[4](#capture-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2729)
|
||||
|
||||
The [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") in a [*simple-capture*](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") shall denote a local entity ([[basic.lookup.unqual]](basic.lookup.unqual "6.5.3 Unqualified name lookup"), [[basic.pre]](basic.pre "6.1 Preamble"))[.](#capture-4.sentence-1)
|
||||
|
||||
The [*simple-capture*](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")*s* this and * this denote the local entity *this[.](#capture-4.sentence-2)
|
||||
|
||||
An entity that is designated by a[*simple-capture*](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") is said to be [*explicitly captured*](#def:explicitly_captured "7.5.6.3 Captures [expr.prim.lambda.capture]")[.](#capture-4.sentence-3)
|
||||
|
||||
[5](#capture-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2738)
|
||||
|
||||
If an [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") in a [*capture*](#nt:capture "7.5.6.3 Captures [expr.prim.lambda.capture]") appears
|
||||
as the [*declarator-id*](dcl.decl.general#nt:declarator-id "9.3.1 General [dcl.decl.general]") of a parameter of
|
||||
the [*lambda-declarator*](#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]")'s [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") or as the name of a template parameter of
|
||||
the [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")'s [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]"),
|
||||
the program is ill-formed[.](#capture-5.sentence-1)
|
||||
|
||||
[*Example [2](#capture-example-2)*: void f() {int x = 0; auto g = [x](int x) { return 0; }; // error: parameter and [*capture*](#nt:capture "7.5.6.3 Captures [expr.prim.lambda.capture]") have the same nameauto h = [y = 0]<typename y>(y) { return 0; }; // error: template parameter and [*capture*](#nt:capture "7.5.6.3 Captures [expr.prim.lambda.capture]")// have the same name} â *end example*]
|
||||
|
||||
[6](#capture-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2756)
|
||||
|
||||
An [*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") inhabits
|
||||
the lambda scope ([[basic.scope.lambda]](basic.scope.lambda "6.4.5 Lambda scope"))
|
||||
of the [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")[.](#capture-6.sentence-1)
|
||||
|
||||
An [*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") without ellipsis
|
||||
behaves as if it declares and explicitly captures a variable of
|
||||
the form âauto [*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") ;â, except that:
|
||||
|
||||
- [(6.1)](#capture-6.1)
|
||||
|
||||
if the capture is by copy (see below), the non-static data member
|
||||
declared for the capture and the variable are treated as two different ways
|
||||
of referring to the same object, which has the lifetime of the non-static
|
||||
data member, and no additional copy and destruction is performed, and
|
||||
|
||||
- [(6.2)](#capture-6.2)
|
||||
|
||||
if the capture is by reference, the variable's lifetime ends when the
|
||||
closure object's lifetime ends[.](#capture-6.sentence-2)
|
||||
|
||||
[*Note [2](#capture-note-2)*:
|
||||
|
||||
This enables an [*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") like
|
||||
âx = std::move(x)â; the second âxâ must bind to a
|
||||
declaration in the surrounding context[.](#capture-6.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [3](#capture-example-3)*: int x = 4;auto y = [&r = x, x = x+1]()->int { r += 2; return x+2; }(); // Updates ::x to 6, and initializes y to 7.auto z = [a = 42](int a) { return 1; }; // error: parameter and conceptual local variable have the same nameauto counter = [i=0]() mutable -> decltype(i) { // OK, returns intreturn i++;}; â *end example*]
|
||||
|
||||
[7](#capture-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2791)
|
||||
|
||||
For the purposes of lambda capture,
|
||||
an expression potentially references local entities as follows:
|
||||
|
||||
- [(7.1)](#capture-7.1)
|
||||
|
||||
An [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") that names a local entity
|
||||
potentially references that entity;
|
||||
an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") that names
|
||||
one or more non-static class members
|
||||
and does not form a pointer to member ([[expr.unary.op]](expr.unary.op "7.6.2.2 Unary operators"))
|
||||
potentially references *this[.](#capture-7.1.sentence-1)
|
||||
[*Note [3](#capture-note-3)*:
|
||||
This occurs even if overload resolution
|
||||
selects a static member function for the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]")[.](#capture-7.1.sentence-2)
|
||||
â *end note*]
|
||||
|
||||
- [(7.2)](#capture-7.2)
|
||||
|
||||
A this expression potentially references *this[.](#capture-7.2.sentence-1)
|
||||
|
||||
- [(7.3)](#capture-7.3)
|
||||
|
||||
A [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") potentially references
|
||||
the local entities named by its [*simple-capture*](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")*s*[.](#capture-7.3.sentence-1)
|
||||
|
||||
If an expression potentially references a local entity
|
||||
within a scope in which it is odr-usable ([[basic.def.odr]](basic.def.odr "6.3 One-definition rule")),
|
||||
and the expression would be potentially evaluated
|
||||
if the effect of any enclosing typeid expressions ([[expr.typeid]](expr.typeid "7.6.1.8 Type identification")) were ignored,
|
||||
the entity is said to be [*implicitly captured*](#def:capture,implicit "7.5.6.3 Captures [expr.prim.lambda.capture]") by each intervening [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") with an associated[*capture-default*](#nt:capture-default "7.5.6.3 Captures [expr.prim.lambda.capture]") that does not explicitly capture it[.](#capture-7.sentence-2)
|
||||
|
||||
The implicit capture of *this is deprecated when the[*capture-default*](#nt:capture-default "7.5.6.3 Captures [expr.prim.lambda.capture]") is =; see [[depr.capture.this]](depr.capture.this "D.3 Implicit capture of *this by reference")[.](#capture-7.sentence-3)
|
||||
|
||||
[*Example [4](#capture-example-4)*: void f(int, const int (&)[2] = {}); // #1void f(const int&, const int (&)[1]); // #2void test() {const int x = 17; auto g = [](auto a) { f(x); // OK, calls #1, does not capture x}; auto g1 = [=](auto a) { f(x); // OK, calls #1, captures x}; auto g2 = [=](auto a) {int selector[sizeof(a) == 1 ? 1 : 2]{};
|
||||
f(x, selector); // OK, captures x, can call #1 or #2}; auto g3 = [=](auto a) {typeid(a + x); // captures x regardless of whether a + x is an unevaluated operand};}
|
||||
|
||||
Within g1, an implementation can optimize away
|
||||
the capture of x as it is not odr-used[.](#capture-7.sentence-4)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[*Note [4](#capture-note-4)*:
|
||||
|
||||
The set of captured entities is determined syntactically,
|
||||
and entities are implicitly captured
|
||||
even if the expression denoting a local entity
|
||||
is within a discarded statement ([[stmt.if]](stmt.if "8.5.2 The if statement"))[.](#capture-7.sentence-5)
|
||||
|
||||
[*Example [5](#capture-example-5)*: template<bool B>void f(int n) {[=](auto a) {if constexpr (B && sizeof(a) > 4) {(void)n; // captures n regardless of the value of B and sizeof(int)}}(0);} â *end example*]
|
||||
|
||||
â *end note*]
|
||||
|
||||
[8](#capture-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2870)
|
||||
|
||||
An entity is [*captured*](#def:captured "7.5.6.3 Captures [expr.prim.lambda.capture]") if it is captured explicitly or implicitly[.](#capture-8.sentence-1)
|
||||
|
||||
An entity
|
||||
captured by a [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") is odr-used ([[basic.def.odr]](basic.def.odr#term.odr.use "6.3 One-definition rule")) by
|
||||
the [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")[.](#capture-8.sentence-2)
|
||||
|
||||
[*Note [5](#capture-note-5)*:
|
||||
|
||||
As a consequence, if a [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") explicitly captures an entity that is not odr-usable,
|
||||
the program is ill-formed ([[basic.def.odr]](basic.def.odr "6.3 One-definition rule"))[.](#capture-8.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [6](#capture-example-6)*:
|
||||
|
||||
[ð](#:Bond,James_Bond)
|
||||
|
||||
void f1(int i) {int const N = 20; auto m1 = [=]{int const M = 30; auto m2 = [i]{int x[N][M]; // OK, N and M are not odr-used x[0][0] = i; // OK, i is explicitly captured by m2 and implicitly captured by m1}; }; struct s1 {int f; void work(int n) {int m = n*n; int j = 40; auto m3 = [this,m] {auto m4 = [&,j] { // error: j not odr-usable due to intervening lambda m3int x = n; // error: n is odr-used but not odr-usable due to intervening lambda m3 x += m; // OK, m implicitly captured by m4 and explicitly captured by m3 x += i; // error: i is odr-used but not odr-usable// due to intervening function and class scopes x += f; // OK, this captured implicitly by m4 and explicitly by m3}; }; }};}struct s2 {double ohseven = .007; auto f() {return [this] {return [*this] {return ohseven; // OK}; }(); }auto g() {return [] {return [*this] { }; // error: *this not captured by outer [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")}(); }}; â *end example*]
|
||||
|
||||
[9](#capture-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2927)
|
||||
|
||||
[*Note [6](#capture-note-6)*:
|
||||
|
||||
Because local entities are not
|
||||
odr-usable within a default argument ([[basic.def.odr]](basic.def.odr "6.3 One-definition rule")),
|
||||
a [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") appearing in a default argument
|
||||
cannot implicitly or explicitly capture any local entity[.](#capture-9.sentence-1)
|
||||
|
||||
Such a [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") can still have an [*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") if
|
||||
any full-expression in its [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]") satisfies the constraints of an expression appearing in
|
||||
a default argument ([[dcl.fct.default]](dcl.fct.default "9.3.4.7 Default arguments"))[.](#capture-9.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [7](#capture-example-7)*: void f2() {int i = 1; void g1(int = ([i]{ return i; })()); // errorvoid g2(int = ([i]{ return 0; })()); // errorvoid g3(int = ([=]{ return i; })()); // errorvoid g4(int = ([=]{ return 0; })()); // OKvoid g5(int = ([]{ return sizeof i; })()); // OKvoid g6(int = ([x=1]{ return x; })()); // OKvoid g7(int = ([x=i]{ return x; })()); // error} â *end example*]
|
||||
|
||||
[10](#capture-10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2954)
|
||||
|
||||
An entity is [*captured by copy*](#def:captured,by_copy "7.5.6.3 Captures [expr.prim.lambda.capture]") if
|
||||
|
||||
- [(10.1)](#capture-10.1)
|
||||
|
||||
it is implicitly captured,
|
||||
the [*capture-default*](#nt:capture-default "7.5.6.3 Captures [expr.prim.lambda.capture]") is =, and
|
||||
the captured entity is not *this, or
|
||||
|
||||
- [(10.2)](#capture-10.2)
|
||||
|
||||
it is explicitly captured with a capture that is not of the formthis,& [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") ...opt, or& ...opt [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]")[.](#capture-10.sentence-1)
|
||||
|
||||
For each entity captured by copy, an
|
||||
unnamed non-static data member is declared in the closure type[.](#capture-10.sentence-2)
|
||||
|
||||
The declaration order of
|
||||
these members is unspecified[.](#capture-10.sentence-3)
|
||||
|
||||
The type of such a data member is
|
||||
the referenced type if the entity is a reference to an object,
|
||||
an lvalue reference to the referenced function type if the entity is a reference to a function, or
|
||||
the type of the corresponding captured entity otherwise[.](#capture-10.sentence-4)
|
||||
|
||||
A member of an anonymous union shall not be captured by copy[.](#capture-10.sentence-5)
|
||||
|
||||
[11](#capture-11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2975)
|
||||
|
||||
Every [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") within the [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") of a[*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") that is an odr-use ([[basic.def.odr]](basic.def.odr#term.odr.use "6.3 One-definition rule")) of an
|
||||
entity captured by copy is transformed into an access to the corresponding unnamed data
|
||||
member of the closure type[.](#capture-11.sentence-1)
|
||||
|
||||
[*Note [7](#capture-note-7)*:
|
||||
|
||||
An [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") that is not an odr-use refers to
|
||||
the original entity, never to a member of the closure type[.](#capture-11.sentence-2)
|
||||
|
||||
However, such
|
||||
an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") can still cause the implicit capture of the
|
||||
entity[.](#capture-11.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
If *this is captured by copy, each expression that odr-uses *this is
|
||||
transformed to instead refer to the corresponding unnamed data member of the closure type[.](#capture-11.sentence-4)
|
||||
|
||||
[*Example [8](#capture-example-8)*: void f(const int*);void g() {const int N = 10; [=] {int arr[N]; // OK, not an odr-use, refers to variable with automatic storage duration f(&N); // OK, causes N to be captured; &N points to// the corresponding member of the closure type};} â *end example*]
|
||||
|
||||
[12](#capture-12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3003)
|
||||
|
||||
An entity is [*captured by reference*](#def:captured,by_reference "7.5.6.3 Captures [expr.prim.lambda.capture]") if it is implicitly or explicitly
|
||||
captured but not captured by copy[.](#capture-12.sentence-1)
|
||||
|
||||
It is unspecified whether additional unnamed
|
||||
non-static data members are declared in the closure type for entities captured by
|
||||
reference[.](#capture-12.sentence-2)
|
||||
|
||||
If declared, such non-static data members shall be of literal type[.](#capture-12.sentence-3)
|
||||
|
||||
[*Example [9](#capture-example-9)*: // The inner closure type must be a literal type regardless of how reference captures are represented.static_assert([](int n) { return [&n] { return ++n; }(); }(3) == 4); â *end example*]
|
||||
|
||||
A bit-field or a member of an anonymous union
|
||||
shall not be captured by reference[.](#capture-12.sentence-4)
|
||||
|
||||
[13](#capture-13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3018)
|
||||
|
||||
An [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") within
|
||||
the [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") of a [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") that is an odr-use of a reference captured by reference
|
||||
refers to the entity to which the captured reference is bound and
|
||||
not to the captured reference[.](#capture-13.sentence-1)
|
||||
|
||||
[*Note [8](#capture-note-8)*:
|
||||
|
||||
The validity of such captures is determined by
|
||||
the lifetime of the object to which the reference refers,
|
||||
not by the lifetime of the reference itself[.](#capture-13.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [10](#capture-example-10)*: auto h(int &r) {return [&] {++r; // Valid after h returns if the lifetime of the// object to which r is bound has not ended};} â *end example*]
|
||||
|
||||
[14](#capture-14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3040)
|
||||
|
||||
If a [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") m2 captures an entity and that entity is
|
||||
captured by an immediately enclosing [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")m1, thenm2's capture is transformed as follows:
|
||||
|
||||
- [(14.1)](#capture-14.1)
|
||||
|
||||
If m1 captures the entity by copy,m2 captures the corresponding
|
||||
non-static data member of m1's closure type;
|
||||
if m1 is not mutable, the non-static data member is considered to be const-qualified[.](#capture-14.1.sentence-1)
|
||||
|
||||
- [(14.2)](#capture-14.2)
|
||||
|
||||
If m1 captures the entity by reference,m2 captures the same
|
||||
entity captured by m1[.](#capture-14.2.sentence-1)
|
||||
|
||||
[*Example [11](#capture-example-11)*:
|
||||
|
||||
The nested [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")*s* and invocations below will output123234[.](#capture-14.sentence-2)
|
||||
|
||||
int a = 1, b = 1, c = 1;auto m1 = [a, &b, &c]() mutable {auto m2 = [a, b, &c]() mutable { std::cout << a << b << c;
|
||||
a = 4; b = 4; c = 4; };
|
||||
a = 3; b = 3; c = 3;
|
||||
m2();};
|
||||
a = 2; b = 2; c = 2;
|
||||
m1();
|
||||
std::cout << a << b << c; â *end example*]
|
||||
|
||||
[15](#capture-15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3073)
|
||||
|
||||
When the [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") is evaluated, the entities that are
|
||||
captured by copy are used to direct-initialize each corresponding non-static data member
|
||||
of the resulting closure object, and the non-static data members corresponding to the[*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")*s* are initialized as indicated by the corresponding[*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]") (which may be copy- or direct-initialization)[.](#capture-15.sentence-1)
|
||||
|
||||
(For array members, the array elements are
|
||||
direct-initialized in increasing subscript order[.](#capture-15.sentence-2))
|
||||
|
||||
These initializations are performed
|
||||
in the (unspecified) order in which the non-static data members are declared[.](#capture-15.sentence-3)
|
||||
|
||||
[*Note [9](#capture-note-9)*:
|
||||
|
||||
This ensures that the destructions will occur in the reverse order of the constructions[.](#capture-15.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[16](#capture-16)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3085)
|
||||
|
||||
[*Note [10](#capture-note-10)*:
|
||||
|
||||
If a non-reference entity is implicitly or explicitly captured by reference,
|
||||
invoking the function call operator of the corresponding [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") after the lifetime of the entity has ended is likely to result in undefined behavior[.](#capture-16.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[17](#capture-17)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3092)
|
||||
|
||||
A [*simple-capture*](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") containing an ellipsis is a pack
|
||||
expansion ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates"))[.](#capture-17.sentence-1)
|
||||
|
||||
An [*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") containing an ellipsis is a pack
|
||||
expansion that declares an[*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") pack ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates"))[.](#capture-17.sentence-2)
|
||||
|
||||
[*Example [12](#capture-example-12)*: template<class... Args>void f(Args... args) {auto lm = [&, args...] { return g(args...); };
|
||||
lm(); auto lm2 = [...xs=std::move(args)] { return g(xs...); };
|
||||
lm2();} â *end example*]
|
||||
411
cppdraft/expr/prim/lambda/capture.md
Normal file
411
cppdraft/expr/prim/lambda/capture.md
Normal file
@@ -0,0 +1,411 @@
|
||||
[expr.prim.lambda.capture]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#lambda.capture)
|
||||
|
||||
### 7.5.6 Lambda expressions [[expr.prim.lambda]](expr.prim.lambda#capture)
|
||||
|
||||
#### 7.5.6.3 Captures [expr.prim.lambda.capture]
|
||||
|
||||
[lambda-capture:](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
[*capture-default*](#nt:capture-default "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
[*capture-list*](#nt:capture-list "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
[*capture-default*](#nt:capture-default "7.5.6.3 Captures [expr.prim.lambda.capture]") , [*capture-list*](#nt:capture-list "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
|
||||
[capture-default:](#nt:capture-default "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
&
|
||||
=
|
||||
|
||||
[capture-list:](#nt:capture-list "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
[*capture*](#nt:capture "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
[*capture-list*](#nt:capture-list "7.5.6.3 Captures [expr.prim.lambda.capture]") , [*capture*](#nt:capture "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
|
||||
[capture:](#nt:capture "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
[*simple-capture*](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
[*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
|
||||
[simple-capture:](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
[*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") ...opt
|
||||
& [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") ...opt
|
||||
this
|
||||
* this
|
||||
|
||||
[init-capture:](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")
|
||||
...opt [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]")
|
||||
& ...opt [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]")
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2672)
|
||||
|
||||
The body of a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") may refer to local entities
|
||||
of enclosing scopes by capturing those entities, as described
|
||||
below[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2677)
|
||||
|
||||
If a [*lambda-capture*](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") includes a [*capture-default*](#nt:capture-default "7.5.6.3 Captures [expr.prim.lambda.capture]") that
|
||||
is &, no identifier in a [*simple-capture*](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") of that[*lambda-capture*](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") shall be preceded
|
||||
by &[.](#2.sentence-1)
|
||||
|
||||
If a [*lambda-capture*](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") includes a[*capture-default*](#nt:capture-default "7.5.6.3 Captures [expr.prim.lambda.capture]") that is =, each[*simple-capture*](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") of that [*lambda-capture*](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") shall
|
||||
be of the form
|
||||
â& [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") ...optâ,
|
||||
âthisâ,
|
||||
or â* thisâ[.](#2.sentence-2)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
The form [&,this] is redundant but accepted
|
||||
for compatibility with C++ 2014[.](#2.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
Ignoring appearances in[*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]")*s* of [*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")*s*, an identifier orthis shall not appear more than once in a[*lambda-capture*](#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")[.](#2.sentence-4)
|
||||
|
||||
[*Example [1](#example-1)*: struct S2 { void f(int i); };void S2::f(int i) {[&, i]{ }; // OK[&, this, i]{ }; // OK, equivalent to [&, i][&, &i]{ }; // error: i preceded by & when & is the default[=, *this]{ }; // OK[=, this]{ }; // OK, equivalent to [=][i, i]{ }; // error: i repeated[this, *this]{ }; // error: this appears twice} â *end example*]
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2711)
|
||||
|
||||
A [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") shall not have
|
||||
a [*capture-default*](#nt:capture-default "7.5.6.3 Captures [expr.prim.lambda.capture]") or [*simple-capture*](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") in its [*lambda-introducer*](expr.prim.lambda.general#nt:lambda-introducer "7.5.6.1 General [expr.prim.lambda.general]") unless
|
||||
|
||||
- [(3.1)](#3.1)
|
||||
|
||||
its innermost enclosing scope is a block scope ([[basic.scope.block]](basic.scope.block "6.4.3 Block scope")),
|
||||
|
||||
- [(3.2)](#3.2)
|
||||
|
||||
it appears within a default member initializer
|
||||
and its innermost enclosing scope is
|
||||
the corresponding class scope ([[basic.scope.class]](basic.scope.class "6.4.7 Class scope")), or
|
||||
|
||||
- [(3.3)](#3.3)
|
||||
|
||||
it appears within a contract assertion
|
||||
and its innermost enclosing scope
|
||||
is the corresponding contract-assertion scope ([[basic.scope.contract]](basic.scope.contract "6.4.10 Contract-assertion scope"))[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2729)
|
||||
|
||||
The [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") in a [*simple-capture*](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") shall denote a local entity ([[basic.lookup.unqual]](basic.lookup.unqual "6.5.3 Unqualified name lookup"), [[basic.pre]](basic.pre "6.1 Preamble"))[.](#4.sentence-1)
|
||||
|
||||
The [*simple-capture*](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")*s* this and * this denote the local entity *this[.](#4.sentence-2)
|
||||
|
||||
An entity that is designated by a[*simple-capture*](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") is said to be [*explicitly captured*](#def:explicitly_captured "7.5.6.3 Captures [expr.prim.lambda.capture]")[.](#4.sentence-3)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2738)
|
||||
|
||||
If an [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") in a [*capture*](#nt:capture "7.5.6.3 Captures [expr.prim.lambda.capture]") appears
|
||||
as the [*declarator-id*](dcl.decl.general#nt:declarator-id "9.3.1 General [dcl.decl.general]") of a parameter of
|
||||
the [*lambda-declarator*](expr.prim.lambda.general#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]")'s [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") or as the name of a template parameter of
|
||||
the [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")'s [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]"),
|
||||
the program is ill-formed[.](#5.sentence-1)
|
||||
|
||||
[*Example [2](#example-2)*: void f() {int x = 0; auto g = [x](int x) { return 0; }; // error: parameter and [*capture*](#nt:capture "7.5.6.3 Captures [expr.prim.lambda.capture]") have the same nameauto h = [y = 0]<typename y>(y) { return 0; }; // error: template parameter and [*capture*](#nt:capture "7.5.6.3 Captures [expr.prim.lambda.capture]")// have the same name} â *end example*]
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2756)
|
||||
|
||||
An [*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") inhabits
|
||||
the lambda scope ([[basic.scope.lambda]](basic.scope.lambda "6.4.5 Lambda scope"))
|
||||
of the [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")[.](#6.sentence-1)
|
||||
|
||||
An [*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") without ellipsis
|
||||
behaves as if it declares and explicitly captures a variable of
|
||||
the form âauto [*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") ;â, except that:
|
||||
|
||||
- [(6.1)](#6.1)
|
||||
|
||||
if the capture is by copy (see below), the non-static data member
|
||||
declared for the capture and the variable are treated as two different ways
|
||||
of referring to the same object, which has the lifetime of the non-static
|
||||
data member, and no additional copy and destruction is performed, and
|
||||
|
||||
- [(6.2)](#6.2)
|
||||
|
||||
if the capture is by reference, the variable's lifetime ends when the
|
||||
closure object's lifetime ends[.](#6.sentence-2)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
This enables an [*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") like
|
||||
âx = std::move(x)â; the second âxâ must bind to a
|
||||
declaration in the surrounding context[.](#6.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [3](#example-3)*: int x = 4;auto y = [&r = x, x = x+1]()->int { r += 2; return x+2; }(); // Updates ::x to 6, and initializes y to 7.auto z = [a = 42](int a) { return 1; }; // error: parameter and conceptual local variable have the same nameauto counter = [i=0]() mutable -> decltype(i) { // OK, returns intreturn i++;}; â *end example*]
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2791)
|
||||
|
||||
For the purposes of lambda capture,
|
||||
an expression potentially references local entities as follows:
|
||||
|
||||
- [(7.1)](#7.1)
|
||||
|
||||
An [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") that names a local entity
|
||||
potentially references that entity;
|
||||
an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") that names
|
||||
one or more non-static class members
|
||||
and does not form a pointer to member ([[expr.unary.op]](expr.unary.op "7.6.2.2 Unary operators"))
|
||||
potentially references *this[.](#7.1.sentence-1)
|
||||
[*Note [3](#note-3)*:
|
||||
This occurs even if overload resolution
|
||||
selects a static member function for the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]")[.](#7.1.sentence-2)
|
||||
â *end note*]
|
||||
|
||||
- [(7.2)](#7.2)
|
||||
|
||||
A this expression potentially references *this[.](#7.2.sentence-1)
|
||||
|
||||
- [(7.3)](#7.3)
|
||||
|
||||
A [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") potentially references
|
||||
the local entities named by its [*simple-capture*](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")*s*[.](#7.3.sentence-1)
|
||||
|
||||
If an expression potentially references a local entity
|
||||
within a scope in which it is odr-usable ([[basic.def.odr]](basic.def.odr "6.3 One-definition rule")),
|
||||
and the expression would be potentially evaluated
|
||||
if the effect of any enclosing typeid expressions ([[expr.typeid]](expr.typeid "7.6.1.8 Type identification")) were ignored,
|
||||
the entity is said to be [*implicitly captured*](#def:capture,implicit "7.5.6.3 Captures [expr.prim.lambda.capture]") by each intervening [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") with an associated[*capture-default*](#nt:capture-default "7.5.6.3 Captures [expr.prim.lambda.capture]") that does not explicitly capture it[.](#7.sentence-2)
|
||||
|
||||
The implicit capture of *this is deprecated when the[*capture-default*](#nt:capture-default "7.5.6.3 Captures [expr.prim.lambda.capture]") is =; see [[depr.capture.this]](depr.capture.this "D.3 Implicit capture of *this by reference")[.](#7.sentence-3)
|
||||
|
||||
[*Example [4](#example-4)*: void f(int, const int (&)[2] = {}); // #1void f(const int&, const int (&)[1]); // #2void test() {const int x = 17; auto g = [](auto a) { f(x); // OK, calls #1, does not capture x}; auto g1 = [=](auto a) { f(x); // OK, calls #1, captures x}; auto g2 = [=](auto a) {int selector[sizeof(a) == 1 ? 1 : 2]{};
|
||||
f(x, selector); // OK, captures x, can call #1 or #2}; auto g3 = [=](auto a) {typeid(a + x); // captures x regardless of whether a + x is an unevaluated operand};}
|
||||
|
||||
Within g1, an implementation can optimize away
|
||||
the capture of x as it is not odr-used[.](#7.sentence-4)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[*Note [4](#note-4)*:
|
||||
|
||||
The set of captured entities is determined syntactically,
|
||||
and entities are implicitly captured
|
||||
even if the expression denoting a local entity
|
||||
is within a discarded statement ([[stmt.if]](stmt.if "8.5.2 The if statement"))[.](#7.sentence-5)
|
||||
|
||||
[*Example [5](#example-5)*: template<bool B>void f(int n) {[=](auto a) {if constexpr (B && sizeof(a) > 4) {(void)n; // captures n regardless of the value of B and sizeof(int)}}(0);} â *end example*]
|
||||
|
||||
â *end note*]
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2870)
|
||||
|
||||
An entity is [*captured*](#def:captured "7.5.6.3 Captures [expr.prim.lambda.capture]") if it is captured explicitly or implicitly[.](#8.sentence-1)
|
||||
|
||||
An entity
|
||||
captured by a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") is odr-used ([[basic.def.odr]](basic.def.odr#term.odr.use "6.3 One-definition rule")) by
|
||||
the [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")[.](#8.sentence-2)
|
||||
|
||||
[*Note [5](#note-5)*:
|
||||
|
||||
As a consequence, if a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") explicitly captures an entity that is not odr-usable,
|
||||
the program is ill-formed ([[basic.def.odr]](basic.def.odr "6.3 One-definition rule"))[.](#8.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [6](#example-6)*:
|
||||
|
||||
[ð](#:Bond,James_Bond)
|
||||
|
||||
void f1(int i) {int const N = 20; auto m1 = [=]{int const M = 30; auto m2 = [i]{int x[N][M]; // OK, N and M are not odr-used x[0][0] = i; // OK, i is explicitly captured by m2 and implicitly captured by m1}; }; struct s1 {int f; void work(int n) {int m = n*n; int j = 40; auto m3 = [this,m] {auto m4 = [&,j] { // error: j not odr-usable due to intervening lambda m3int x = n; // error: n is odr-used but not odr-usable due to intervening lambda m3 x += m; // OK, m implicitly captured by m4 and explicitly captured by m3 x += i; // error: i is odr-used but not odr-usable// due to intervening function and class scopes x += f; // OK, this captured implicitly by m4 and explicitly by m3}; }; }};}struct s2 {double ohseven = .007; auto f() {return [this] {return [*this] {return ohseven; // OK}; }(); }auto g() {return [] {return [*this] { }; // error: *this not captured by outer [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")}(); }}; â *end example*]
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2927)
|
||||
|
||||
[*Note [6](#note-6)*:
|
||||
|
||||
Because local entities are not
|
||||
odr-usable within a default argument ([[basic.def.odr]](basic.def.odr "6.3 One-definition rule")),
|
||||
a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") appearing in a default argument
|
||||
cannot implicitly or explicitly capture any local entity[.](#9.sentence-1)
|
||||
|
||||
Such a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") can still have an [*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") if
|
||||
any full-expression in its [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]") satisfies the constraints of an expression appearing in
|
||||
a default argument ([[dcl.fct.default]](dcl.fct.default "9.3.4.7 Default arguments"))[.](#9.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [7](#example-7)*: void f2() {int i = 1; void g1(int = ([i]{ return i; })()); // errorvoid g2(int = ([i]{ return 0; })()); // errorvoid g3(int = ([=]{ return i; })()); // errorvoid g4(int = ([=]{ return 0; })()); // OKvoid g5(int = ([]{ return sizeof i; })()); // OKvoid g6(int = ([x=1]{ return x; })()); // OKvoid g7(int = ([x=i]{ return x; })()); // error} â *end example*]
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2954)
|
||||
|
||||
An entity is [*captured by copy*](#def:captured,by_copy "7.5.6.3 Captures [expr.prim.lambda.capture]") if
|
||||
|
||||
- [(10.1)](#10.1)
|
||||
|
||||
it is implicitly captured,
|
||||
the [*capture-default*](#nt:capture-default "7.5.6.3 Captures [expr.prim.lambda.capture]") is =, and
|
||||
the captured entity is not *this, or
|
||||
|
||||
- [(10.2)](#10.2)
|
||||
|
||||
it is explicitly captured with a capture that is not of the formthis,& [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") ...opt, or& ...opt [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]")[.](#10.sentence-1)
|
||||
|
||||
For each entity captured by copy, an
|
||||
unnamed non-static data member is declared in the closure type[.](#10.sentence-2)
|
||||
|
||||
The declaration order of
|
||||
these members is unspecified[.](#10.sentence-3)
|
||||
|
||||
The type of such a data member is
|
||||
the referenced type if the entity is a reference to an object,
|
||||
an lvalue reference to the referenced function type if the entity is a reference to a function, or
|
||||
the type of the corresponding captured entity otherwise[.](#10.sentence-4)
|
||||
|
||||
A member of an anonymous union shall not be captured by copy[.](#10.sentence-5)
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2975)
|
||||
|
||||
Every [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") within the [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") of a[*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") that is an odr-use ([[basic.def.odr]](basic.def.odr#term.odr.use "6.3 One-definition rule")) of an
|
||||
entity captured by copy is transformed into an access to the corresponding unnamed data
|
||||
member of the closure type[.](#11.sentence-1)
|
||||
|
||||
[*Note [7](#note-7)*:
|
||||
|
||||
An [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") that is not an odr-use refers to
|
||||
the original entity, never to a member of the closure type[.](#11.sentence-2)
|
||||
|
||||
However, such
|
||||
an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") can still cause the implicit capture of the
|
||||
entity[.](#11.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
If *this is captured by copy, each expression that odr-uses *this is
|
||||
transformed to instead refer to the corresponding unnamed data member of the closure type[.](#11.sentence-4)
|
||||
|
||||
[*Example [8](#example-8)*: void f(const int*);void g() {const int N = 10; [=] {int arr[N]; // OK, not an odr-use, refers to variable with automatic storage duration f(&N); // OK, causes N to be captured; &N points to// the corresponding member of the closure type};} â *end example*]
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3003)
|
||||
|
||||
An entity is [*captured by reference*](#def:captured,by_reference "7.5.6.3 Captures [expr.prim.lambda.capture]") if it is implicitly or explicitly
|
||||
captured but not captured by copy[.](#12.sentence-1)
|
||||
|
||||
It is unspecified whether additional unnamed
|
||||
non-static data members are declared in the closure type for entities captured by
|
||||
reference[.](#12.sentence-2)
|
||||
|
||||
If declared, such non-static data members shall be of literal type[.](#12.sentence-3)
|
||||
|
||||
[*Example [9](#example-9)*: // The inner closure type must be a literal type regardless of how reference captures are represented.static_assert([](int n) { return [&n] { return ++n; }(); }(3) == 4); â *end example*]
|
||||
|
||||
A bit-field or a member of an anonymous union
|
||||
shall not be captured by reference[.](#12.sentence-4)
|
||||
|
||||
[13](#13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3018)
|
||||
|
||||
An [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") within
|
||||
the [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") of a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") that is an odr-use of a reference captured by reference
|
||||
refers to the entity to which the captured reference is bound and
|
||||
not to the captured reference[.](#13.sentence-1)
|
||||
|
||||
[*Note [8](#note-8)*:
|
||||
|
||||
The validity of such captures is determined by
|
||||
the lifetime of the object to which the reference refers,
|
||||
not by the lifetime of the reference itself[.](#13.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [10](#example-10)*: auto h(int &r) {return [&] {++r; // Valid after h returns if the lifetime of the// object to which r is bound has not ended};} â *end example*]
|
||||
|
||||
[14](#14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3040)
|
||||
|
||||
If a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") m2 captures an entity and that entity is
|
||||
captured by an immediately enclosing [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")m1, thenm2's capture is transformed as follows:
|
||||
|
||||
- [(14.1)](#14.1)
|
||||
|
||||
If m1 captures the entity by copy,m2 captures the corresponding
|
||||
non-static data member of m1's closure type;
|
||||
if m1 is not mutable, the non-static data member is considered to be const-qualified[.](#14.1.sentence-1)
|
||||
|
||||
- [(14.2)](#14.2)
|
||||
|
||||
If m1 captures the entity by reference,m2 captures the same
|
||||
entity captured by m1[.](#14.2.sentence-1)
|
||||
|
||||
[*Example [11](#example-11)*:
|
||||
|
||||
The nested [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")*s* and invocations below will output123234[.](#14.sentence-2)
|
||||
|
||||
int a = 1, b = 1, c = 1;auto m1 = [a, &b, &c]() mutable {auto m2 = [a, b, &c]() mutable { std::cout << a << b << c;
|
||||
a = 4; b = 4; c = 4; };
|
||||
a = 3; b = 3; c = 3;
|
||||
m2();};
|
||||
a = 2; b = 2; c = 2;
|
||||
m1();
|
||||
std::cout << a << b << c; â *end example*]
|
||||
|
||||
[15](#15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3073)
|
||||
|
||||
When the [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") is evaluated, the entities that are
|
||||
captured by copy are used to direct-initialize each corresponding non-static data member
|
||||
of the resulting closure object, and the non-static data members corresponding to the[*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")*s* are initialized as indicated by the corresponding[*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]") (which may be copy- or direct-initialization)[.](#15.sentence-1)
|
||||
|
||||
(For array members, the array elements are
|
||||
direct-initialized in increasing subscript order[.](#15.sentence-2))
|
||||
|
||||
These initializations are performed
|
||||
in the (unspecified) order in which the non-static data members are declared[.](#15.sentence-3)
|
||||
|
||||
[*Note [9](#note-9)*:
|
||||
|
||||
This ensures that the destructions will occur in the reverse order of the constructions[.](#15.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[16](#16)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3085)
|
||||
|
||||
[*Note [10](#note-10)*:
|
||||
|
||||
If a non-reference entity is implicitly or explicitly captured by reference,
|
||||
invoking the function call operator of the corresponding [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") after the lifetime of the entity has ended is likely to result in undefined behavior[.](#16.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[17](#17)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3092)
|
||||
|
||||
A [*simple-capture*](#nt:simple-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") containing an ellipsis is a pack
|
||||
expansion ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates"))[.](#17.sentence-1)
|
||||
|
||||
An [*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") containing an ellipsis is a pack
|
||||
expansion that declares an[*init-capture*](#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") pack ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates"))[.](#17.sentence-2)
|
||||
|
||||
[*Example [12](#example-12)*: template<class... Args>void f(Args... args) {auto lm = [&, args...] { return g(args...); };
|
||||
lm(); auto lm2 = [...xs=std::move(args)] { return g(xs...); };
|
||||
lm2();} â *end example*]
|
||||
377
cppdraft/expr/prim/lambda/closure.md
Normal file
377
cppdraft/expr/prim/lambda/closure.md
Normal file
@@ -0,0 +1,377 @@
|
||||
[expr.prim.lambda.closure]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#lambda.closure)
|
||||
|
||||
### 7.5.6 Lambda expressions [[expr.prim.lambda]](expr.prim.lambda#closure)
|
||||
|
||||
#### 7.5.6.2 Closure types [expr.prim.lambda.closure]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2198)
|
||||
|
||||
The type of a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") (which is also the type of the
|
||||
closure object) is a unique, unnamed non-union class type,
|
||||
called the [*closure type*](#def:closure_type "7.5.6.2 Closure types [expr.prim.lambda.closure]"),
|
||||
whose properties are described below[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2204)
|
||||
|
||||
The closure type is not complete
|
||||
until the end of its corresponding [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]")[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2208)
|
||||
|
||||
The closure type is declared in the smallest block
|
||||
scope, class scope, or namespace scope that contains the corresponding[*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")[.](#3.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
This determines the set of namespaces and
|
||||
classes associated with the closure type ([[basic.lookup.argdep]](basic.lookup.argdep "6.5.4 Argument-dependent name lookup"))[.](#3.sentence-2)
|
||||
|
||||
The parameter
|
||||
types of a [*lambda-declarator*](expr.prim.lambda.general#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]") do not affect these associated namespaces and
|
||||
classes[.](#3.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2219)
|
||||
|
||||
The closure type is not an aggregate type ([[dcl.init.aggr]](dcl.init.aggr "9.5.2 Aggregates"));
|
||||
it is a structural type ([[temp.param]](temp.param#term.structural.type "13.2 Template parameters")) if and only if
|
||||
the lambda has no [*lambda-capture*](expr.prim.lambda.capture#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")[.](#4.sentence-1)
|
||||
|
||||
An implementation may define the closure type differently from what
|
||||
is described below provided this does not alter the observable behavior of the program
|
||||
other than by changing:
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
the size and/or alignment of the closure type,
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
whether the closure type is trivially copyable ([[class.prop]](class.prop "11.2 Properties of classes")),
|
||||
|
||||
- [(4.3)](#4.3)
|
||||
|
||||
whether the closure type is trivially relocatable ([[class.prop]](class.prop "11.2 Properties of classes")),
|
||||
|
||||
- [(4.4)](#4.4)
|
||||
|
||||
whether the closure type is replaceable ([[class.prop]](class.prop "11.2 Properties of classes")), or
|
||||
|
||||
- [(4.5)](#4.5)
|
||||
|
||||
whether the closure type is a standard-layout class ([[class.prop]](class.prop "11.2 Properties of classes"))[.](#4.sentence-2)
|
||||
|
||||
An implementation shall not add members of rvalue reference type to the closure
|
||||
type[.](#4.sentence-3)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2237)
|
||||
|
||||
The closure type for a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") has a public
|
||||
inline function call operator (for a non-generic lambda) or
|
||||
function call operator template (for a generic lambda) ([[over.call]](over.call "12.4.4 Function call"))
|
||||
whose parameters and return type
|
||||
are those of the [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")'s[*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") and [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]") respectively, and whose[*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]") consists of
|
||||
the specified [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]"), if any[.](#5.sentence-1)
|
||||
|
||||
The function call operator or the function call operator template are
|
||||
direct members of the closure type[.](#5.sentence-2)
|
||||
|
||||
The [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") of the function call operator template
|
||||
is the [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") immediately following< [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]") >, if any[.](#5.sentence-3)
|
||||
|
||||
The trailing [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") of the function call operator
|
||||
or operator template is the [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") of the [*lambda-declarator*](expr.prim.lambda.general#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]"), if any[.](#5.sentence-4)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
The function call operator template for a generic lambda can be
|
||||
an abbreviated function template ([[dcl.fct]](dcl.fct "9.3.4.6 Functions"))[.](#5.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [1](#example-1)*: auto glambda = [](auto a, auto&& b) { return a < b; };bool b = glambda(3, 3.14); // OKauto vglambda = [](auto printer) {return [=](auto&& ... ts) { // OK, ts is a function parameter pack printer(std::forward<decltype(ts)>(ts)...); return [=]() { printer(ts ...); }; };};auto p = vglambda( [](auto v1, auto v2, auto v3){ std::cout << v1 << v2 << v3; } );auto q = p(1, 'a', 3.14); // OK, outputs 1a3.14 q(); // OK, outputs 1a3.14auto fact = [](this auto self, int n) -> int { // OK, explicit object parameterreturn (n <= 1) ? 1 : n * self(n-1);};
|
||||
std::cout << fact(5); // OK, outputs 120 â *end example*]
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2285)
|
||||
|
||||
Given a lambda with a [*lambda-capture*](expr.prim.lambda.capture#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]"),
|
||||
the type of the explicit object parameter, if any,
|
||||
of the lambda's function call operator
|
||||
(possibly instantiated from a function call operator template)
|
||||
shall be either:
|
||||
|
||||
- [(6.1)](#6.1)
|
||||
|
||||
the closure type,
|
||||
|
||||
- [(6.2)](#6.2)
|
||||
|
||||
a class type publicly and unambiguously derived from the closure type, or
|
||||
|
||||
- [(6.3)](#6.3)
|
||||
|
||||
a reference to a possibly cv-qualified such type[.](#6.sentence-1)
|
||||
|
||||
[*Example [2](#example-2)*: struct C {template <typename T> C(T);};
|
||||
|
||||
void func(int i) {int x = [=](this auto&&) { return i; }(); // OKint y = [=](this C) { return i; }(); // errorint z = [](this C) { return 42; }(); // OK} â *end example*]
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2314)
|
||||
|
||||
The function call operator or operator template is
|
||||
a static member function or static member function template ([[class.static.mfct]](class.static.mfct "11.4.9.2 Static member functions"))
|
||||
if the [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")'s[*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") is followed by static[.](#7.sentence-1)
|
||||
|
||||
Otherwise, it is
|
||||
a non-static member function or member function template ([[class.mfct.non.static]](class.mfct.non.static "11.4.3 Non-static member functions"))
|
||||
that is declaredconst ([[class.mfct.non.static]](class.mfct.non.static "11.4.3 Non-static member functions")) if and only if the[*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")'s [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") is not
|
||||
followed by mutable and
|
||||
the [*lambda-declarator*](expr.prim.lambda.general#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]") does not contain
|
||||
an explicit object parameter[.](#7.sentence-2)
|
||||
|
||||
It is neither virtual nor declared volatile[.](#7.sentence-3)
|
||||
|
||||
Any [*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5 Exception specifications [except.spec]") or [*function-contract-specifier*](dcl.contract.func#nt:function-contract-specifier "9.4.1 General [dcl.contract.func]") ([[dcl.contract.func]](dcl.contract.func "9.4.1 General"))
|
||||
specified on a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") applies to the corresponding function call operator or operator template[.](#7.sentence-4)
|
||||
|
||||
An [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") in a [*lambda-declarator*](expr.prim.lambda.general#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]") appertains
|
||||
to the type of the corresponding function call operator or operator template[.](#7.sentence-5)
|
||||
|
||||
An [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") in a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") preceding a [*lambda-declarator*](expr.prim.lambda.general#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]") appertains to the corresponding function call operator or operator template[.](#7.sentence-6)
|
||||
|
||||
The function call operator or any given operator template specialization
|
||||
is a constexpr function if either
|
||||
the corresponding [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")'s[*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") is followed by constexpr or consteval, or
|
||||
it is constexpr-suitable ([[dcl.constexpr]](dcl.constexpr "9.2.6 The constexpr and consteval specifiers"))[.](#7.sentence-7)
|
||||
|
||||
It is an immediate function ([[dcl.constexpr]](dcl.constexpr "9.2.6 The constexpr and consteval specifiers"))
|
||||
if the corresponding [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")'s[*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") is followed by consteval[.](#7.sentence-8)
|
||||
|
||||
[*Example [3](#example-3)*: auto ID = [](auto a) { return a; };static_assert(ID(3) == 3); // OKstruct NonLiteral { NonLiteral(int n) : n(n) { }int n;};static_assert(ID(NonLiteral{3}).n == 3); // error â *end example*]
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2358)
|
||||
|
||||
[*Example [4](#example-4)*: auto monoid = [](auto v) { return [=] { return v; }; };auto add = [](auto m1) constexpr {auto ret = m1(); return [=](auto m2) mutable {auto m1val = m1(); auto plus = [=](auto m2val) mutable constexpr{ return m1val += m2val; };
|
||||
ret = plus(m2()); return monoid(ret); };};constexpr auto zero = monoid(0);constexpr auto one = monoid(1);static_assert(add(one)(zero)() == one()); // OK// Since two below is not declared constexpr, an evaluation of its constexpr member function call operator// cannot perform an lvalue-to-rvalue conversion on one of its subobjects (that represents its capture)// in a constant expression.auto two = monoid(2);
|
||||
assert(two() == 2); // OK, not a constant expression.static_assert(add(one)(one)() == two()); // error: two() is not a constant expressionstatic_assert(add(one)(one)() == monoid(2)()); // OK â *end example*]
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2386)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
The function call operator or operator template can be constrained ([[temp.constr.decl]](temp.constr.decl "13.5.3 Constrained declarations"))
|
||||
by a [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]") ([[temp.param]](temp.param "13.2 Template parameters")),
|
||||
a [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") ([[temp.pre]](temp.pre "13.1 Preamble")),
|
||||
or a trailing [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") ([[dcl.decl]](dcl.decl "9.3 Declarators"))[.](#9.sentence-1)
|
||||
|
||||
[*Example [5](#example-5)*: template <typename T> concept C1 = /* ... */;template <std::size_t N> concept C2 = /* ... */;template <typename A, typename B> concept C3 = /* ... */;
|
||||
|
||||
auto f = []<typename T1, C1 T2> requires C2<sizeof(T1) + sizeof(T2)>(T1 a1, T1 b1, T2 a2, auto a3, auto a4) requires C3<decltype(a4), T2> {// T2 is constrained by a [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]").// T1 and T2 are constrained by a [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]"), and// T2 and the type of a4 are constrained by a trailing [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]").}; â *end example*]
|
||||
|
||||
â *end note*]
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2408)
|
||||
|
||||
If all potential references
|
||||
to a local entity implicitly captured by a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") L occur within the function contract assertions ([[dcl.contract.func]](dcl.contract.func "9.4.1 General"))
|
||||
of the call operator or operator template of L or within [*assertion-statement*](stmt.contract.assert#nt:assertion-statement "8.9 Assertion statement [stmt.contract.assert]")*s* ([[stmt.contract.assert]](stmt.contract.assert "8.9 Assertion statement"))
|
||||
within the body of L,
|
||||
the program is ill-formed[.](#10.sentence-1)
|
||||
|
||||
[*Note [4](#note-4)*:
|
||||
|
||||
Adding a contract assertion to an existing C++ program cannot
|
||||
cause additional captures[.](#10.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [6](#example-6)*: static int i = 0;
|
||||
|
||||
void test() {auto f1 = [=] pre(i > 0) {}; // OK, no local entities are captured.int i = 1; auto f2 = [=] pre(i > 0) {}; // error: cannot implicitly capture i hereauto f3 = [i] pre(i > 0) {}; // OK, i is captured explicitly.auto f4 = [=] {contract_assert(i > 0); // error: cannot implicitly capture i here}; auto f5 = [=] {contract_assert(i > 0); // OK, i is referenced elsewhere.(void)i; }; auto f6 = [=] pre( // #1[]{bool x = true; return [=]{ return x; }(); // OK, #1 captures nothing.}()) {}; bool y = true; auto f7 = [=] pre([=]{ return y; }()); // error: outer capture of y is invalid.} â *end example*]
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2453)
|
||||
|
||||
The closure type for a non-generic [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") with no[*lambda-capture*](expr.prim.lambda.capture#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") and no explicit object parameter ([[dcl.fct]](dcl.fct "9.3.4.6 Functions"))
|
||||
whose constraints (if any) are satisfied
|
||||
has a conversion function to pointer to
|
||||
function with C++ language [linkage](dcl.link "9.12 Linkage specifications [dcl.link]") having
|
||||
the same parameter and return types as the closure type's function call operator[.](#11.sentence-1)
|
||||
|
||||
The conversion is to âpointer to noexcept functionâ
|
||||
if the function call operator
|
||||
has a non-throwing exception specification[.](#11.sentence-2)
|
||||
|
||||
If the function call operator is a static member function,
|
||||
then the value returned by this conversion function is
|
||||
a pointer to the function call operator[.](#11.sentence-3)
|
||||
|
||||
Otherwise, the value returned by this conversion function
|
||||
is a pointer to a function F that, when invoked,
|
||||
has the same effect as invoking the closure type's function call operator
|
||||
on a default-constructed instance of the closure type[.](#11.sentence-4)
|
||||
|
||||
F is a constexpr function
|
||||
if the function call operator is a constexpr function
|
||||
and is an immediate function
|
||||
if the function call operator is an immediate function[.](#11.sentence-5)
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2476)
|
||||
|
||||
For a generic lambda with no [*lambda-capture*](expr.prim.lambda.capture#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") and no explicit object parameter ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")),
|
||||
the closure type has a
|
||||
conversion function template to
|
||||
pointer to function[.](#12.sentence-1)
|
||||
|
||||
The conversion function template has the same invented
|
||||
template parameter list, and the pointer to function has the same
|
||||
parameter types, as the function call operator template[.](#12.sentence-2)
|
||||
|
||||
The return type of
|
||||
the pointer to function shall behave as if it were a[*decltype-specifier*](dcl.type.decltype#nt:decltype-specifier "9.2.9.6 Decltype specifiers [dcl.type.decltype]") denoting the return type of the corresponding
|
||||
function call operator template specialization[.](#12.sentence-3)
|
||||
|
||||
[13](#13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2488)
|
||||
|
||||
[*Note [5](#note-5)*:
|
||||
|
||||
If the generic lambda has no [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]") or
|
||||
the [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]") contains a placeholder type, return type
|
||||
deduction of the corresponding function call operator template specialization
|
||||
has to be done[.](#13.sentence-1)
|
||||
|
||||
The corresponding specialization is that instantiation of the
|
||||
function call operator template with the same template arguments as those
|
||||
deduced for the conversion function template[.](#13.sentence-2)
|
||||
|
||||
Consider the following:auto glambda = [](auto a) { return a; };int (*fp)(int) = glambda;
|
||||
|
||||
The behavior of the conversion function of glambda above is like
|
||||
that of the following conversion function:struct Closure {template<class T> auto operator()(T t) const { /* ... */ }template<class T> static auto lambda_call_operator_invoker(T a) {// forwards execution to operator()(a) and therefore has// the same return type deduced/* ... */}template<class T> using fptr_t =decltype(lambda_call_operator_invoker(declval<T>())) (*)(T); template<class T> operator fptr_t<T>() const{ return &lambda_call_operator_invoker; }};
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [7](#example-7)*: void f1(int (*)(int)) { }void f2(char (*)(int)) { }void g(int (*)(int)) { } // #1void g(char (*)(char)) { } // #2void h(int (*)(int)) { } // #3void h(char (*)(int)) { } // #4auto glambda = [](auto a) { return a; };
|
||||
f1(glambda); // OK f2(glambda); // error: ID is not convertible g(glambda); // error: ambiguous h(glambda); // OK, calls #3 since it is convertible from IDint& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK â *end example*]
|
||||
|
||||
[14](#14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2539)
|
||||
|
||||
If the function call operator template is a static member function template,
|
||||
then the value returned by
|
||||
any given specialization of this conversion function template is
|
||||
a pointer to the corresponding function call operator template specialization[.](#14.sentence-1)
|
||||
|
||||
Otherwise,
|
||||
the value returned by any given specialization of this conversion function
|
||||
template is a pointer to a function F that, when invoked, has the same
|
||||
effect as invoking the generic lambda's corresponding function call operator
|
||||
template specialization on a default-constructed instance of the closure type[.](#14.sentence-2)
|
||||
|
||||
F is a constexpr function
|
||||
if the corresponding specialization is a constexpr function andF is an immediate function
|
||||
if the function call operator template specialization is an immediate function[.](#14.sentence-3)
|
||||
|
||||
[*Note [6](#note-6)*:
|
||||
|
||||
This will result in the implicit instantiation of the generic lambda's body[.](#14.sentence-4)
|
||||
|
||||
The instantiated generic lambda's return type and parameter types need to match
|
||||
the return type and parameter types of the pointer to function[.](#14.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [8](#example-8)*: auto GL = [](auto a) { std::cout << a; return a; };int (*GL_int)(int) = GL; // OK, through conversion function template GL_int(3); // OK, same as GL(3) â *end example*]
|
||||
|
||||
[15](#15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2566)
|
||||
|
||||
The conversion function or conversion function template is public,
|
||||
constexpr, non-virtual, non-explicit, const, and has a non-throwing [exception
|
||||
specification](except.spec "14.5 Exception specifications [except.spec]")[.](#15.sentence-1)
|
||||
|
||||
[*Example [9](#example-9)*: auto Fwd = [](int (*fp)(int), auto a) { return fp(a); };auto C = [](auto a) { return a; };
|
||||
|
||||
static_assert(Fwd(C,3) == 3); // OK// No specialization of the function call operator template can be constexpr (due to the local static).auto NC = [](auto a) { static int s; return a; };static_assert(Fwd(NC,3) == 3); // error â *end example*]
|
||||
|
||||
[16](#16)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2583)
|
||||
|
||||
The [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")'s [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") yields
|
||||
the [*function-body*](dcl.fct.def.general#nt:function-body "9.6.1 General [dcl.fct.def.general]") ([[dcl.fct.def]](dcl.fct.def "9.6 Function definitions")) of the function call operator,
|
||||
but it is not within the scope of the closure type[.](#16.sentence-1)
|
||||
|
||||
[*Example [10](#example-10)*: struct S1 {int x, y; int operator()(int); void f() {[=]()->int {return operator()(this->x + y); // equivalent to S1::operator()(this->x + (*this).y)// this has type S1*}; }}; â *end example*]
|
||||
|
||||
Unless the [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") is
|
||||
that of a [*consteval-block-declaration*](dcl.pre#nt:consteval-block-declaration "9.1 Preamble [dcl.pre]") ([[dcl.pre]](dcl.pre "9.1 Preamble")),
|
||||
a variable __func__ is implicitly defined at the beginning of
|
||||
the [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") of the [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]"),
|
||||
with semantics as described in [[dcl.fct.def.general]](dcl.fct.def.general "9.6.1 General")[.](#16.sentence-2)
|
||||
|
||||
[17](#17)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2607)
|
||||
|
||||
The closure type associated with a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") has no
|
||||
default constructor
|
||||
if the [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") has a [*lambda-capture*](expr.prim.lambda.capture#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") and a defaulted default constructor otherwise[.](#17.sentence-1)
|
||||
|
||||
It has a defaulted copy constructor and a defaulted move constructor ([[class.copy.ctor]](class.copy.ctor "11.4.5.3 Copy/move constructors"))[.](#17.sentence-2)
|
||||
|
||||
It has a deleted copy assignment operator if the [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") has a [*lambda-capture*](expr.prim.lambda.capture#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") and defaulted copy and move assignment
|
||||
operators otherwise ([[class.copy.assign]](class.copy.assign "11.4.6 Copy/move assignment operator"))[.](#17.sentence-3)
|
||||
|
||||
[*Note [7](#note-7)*:
|
||||
|
||||
These special member functions are implicitly defined as
|
||||
usual, which can result in them being defined as deleted[.](#17.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[18](#18)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2621)
|
||||
|
||||
The closure type associated with a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") has an
|
||||
implicitly-declared destructor ([[class.dtor]](class.dtor "11.4.7 Destructors"))[.](#18.sentence-1)
|
||||
|
||||
[19](#19)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2625)
|
||||
|
||||
A member of a closure type shall not be[explicitly instantiated](temp.explicit "13.9.3 Explicit instantiation [temp.explicit]"),[explicitly specialized](temp.expl.spec "13.9.4 Explicit specialization [temp.expl.spec]"), or
|
||||
named in a [friend declaration](class.friend "11.8.4 Friends [class.friend]")[.](#19.sentence-1)
|
||||
131
cppdraft/expr/prim/lambda/general.md
Normal file
131
cppdraft/expr/prim/lambda/general.md
Normal file
@@ -0,0 +1,131 @@
|
||||
[expr.prim.lambda.general]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#lambda.general)
|
||||
|
||||
### 7.5.6 Lambda expressions [[expr.prim.lambda]](expr.prim.lambda#general)
|
||||
|
||||
#### 7.5.6.1 General [expr.prim.lambda.general]
|
||||
|
||||
[lambda-expression:](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")
|
||||
[*lambda-introducer*](#nt:lambda-introducer "7.5.6.1 General [expr.prim.lambda.general]") [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt [*lambda-declarator*](#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]") [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]")
|
||||
[*lambda-introducer*](#nt:lambda-introducer "7.5.6.1 General [expr.prim.lambda.general]") < [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]") > [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]")opt [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt
|
||||
[*lambda-declarator*](#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]") [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]")
|
||||
|
||||
[lambda-introducer:](#nt:lambda-introducer "7.5.6.1 General [expr.prim.lambda.general]")
|
||||
[ [*lambda-capture*](expr.prim.lambda.capture#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")opt ]
|
||||
|
||||
[lambda-declarator:](#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]")
|
||||
[*lambda-specifier-seq*](#nt:lambda-specifier-seq "7.5.6.1 General [expr.prim.lambda.general]") [*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5 Exception specifications [except.spec]")opt [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]")opt
|
||||
[*function-contract-specifier-seq*](dcl.contract.func#nt:function-contract-specifier-seq "9.4.1 General [dcl.contract.func]")opt
|
||||
[*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5 Exception specifications [except.spec]") [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]")opt [*function-contract-specifier-seq*](dcl.contract.func#nt:function-contract-specifier-seq "9.4.1 General [dcl.contract.func]")opt
|
||||
[*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]")opt [*function-contract-specifier-seq*](dcl.contract.func#nt:function-contract-specifier-seq "9.4.1 General [dcl.contract.func]")opt
|
||||
( [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") ) [*lambda-specifier-seq*](#nt:lambda-specifier-seq "7.5.6.1 General [expr.prim.lambda.general]")opt [*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5 Exception specifications [except.spec]")opt [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt
|
||||
[*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]")opt [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]")opt [*function-contract-specifier-seq*](dcl.contract.func#nt:function-contract-specifier-seq "9.4.1 General [dcl.contract.func]")opt
|
||||
|
||||
[lambda-specifier:](#nt:lambda-specifier "7.5.6.1 General [expr.prim.lambda.general]")
|
||||
consteval
|
||||
constexpr
|
||||
mutable
|
||||
static
|
||||
|
||||
[lambda-specifier-seq:](#nt:lambda-specifier-seq "7.5.6.1 General [expr.prim.lambda.general]")
|
||||
[*lambda-specifier*](#nt:lambda-specifier "7.5.6.1 General [expr.prim.lambda.general]") [*lambda-specifier-seq*](#nt:lambda-specifier-seq "7.5.6.1 General [expr.prim.lambda.general]")opt
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2106)
|
||||
|
||||
A [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") provides
|
||||
a concise way to create a simple function object[.](#1.sentence-1)
|
||||
|
||||
[*Example [1](#example-1)*: #include <algorithm>#include <cmath>void abssort(float* x, unsigned N) { std::sort(x, x + N, [](float a, float b) { return std::abs(a) < std::abs(b); });} â *end example*]
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2119)
|
||||
|
||||
A [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") is a prvalue
|
||||
whose result object is called the [*closure object*](#def:closure_object "7.5.6.1 General [expr.prim.lambda.general]")[.](#2.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
A closure object behaves like a [function
|
||||
object](function.objects "22.10 Function objects [function.objects]")[.](#2.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2127)
|
||||
|
||||
An ambiguity can arise
|
||||
because a [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") can end in
|
||||
an [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]"),
|
||||
which collides with
|
||||
the [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") in [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")[.](#3.sentence-1)
|
||||
|
||||
In such cases,
|
||||
any attributes are treated as[*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") in [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")[.](#3.sentence-2)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
Such ambiguous cases cannot have valid semantics
|
||||
because the constraint expression would not have type bool[.](#3.sentence-3)
|
||||
|
||||
[*Example [2](#example-2)*: auto x = []<class T> requires T::operator int [[some_attribute]] (int) { } â *end example*]
|
||||
|
||||
â *end note*]
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2146)
|
||||
|
||||
A [*lambda-specifier-seq*](#nt:lambda-specifier-seq "7.5.6.1 General [expr.prim.lambda.general]") shall contain at most one of each [*lambda-specifier*](#nt:lambda-specifier "7.5.6.1 General [expr.prim.lambda.general]") and
|
||||
shall not contain both constexpr and consteval[.](#4.sentence-1)
|
||||
|
||||
If the [*lambda-declarator*](#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]") contains
|
||||
an explicit object parameter ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")),
|
||||
then no [*lambda-specifier*](#nt:lambda-specifier "7.5.6.1 General [expr.prim.lambda.general]") in the [*lambda-specifier-seq*](#nt:lambda-specifier-seq "7.5.6.1 General [expr.prim.lambda.general]") shall be mutable or static[.](#4.sentence-2)
|
||||
|
||||
The [*lambda-specifier-seq*](#nt:lambda-specifier-seq "7.5.6.1 General [expr.prim.lambda.general]") shall not contain
|
||||
both mutable and static[.](#4.sentence-3)
|
||||
|
||||
If the [*lambda-specifier-seq*](#nt:lambda-specifier-seq "7.5.6.1 General [expr.prim.lambda.general]") contains static,
|
||||
there shall be no [*lambda-capture*](expr.prim.lambda.capture#nt:lambda-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")[.](#4.sentence-4)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
The trailing [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") is described in [[dcl.decl]](dcl.decl "9.3 Declarators")[.](#4.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2162)
|
||||
|
||||
A [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")'s [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") is the [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") of
|
||||
the [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")'s [*lambda-declarator*](#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]"), if any,
|
||||
or empty otherwise[.](#5.sentence-1)
|
||||
|
||||
If the [*lambda-declarator*](#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]") does not include a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]"),
|
||||
it is considered to be -> auto[.](#5.sentence-2)
|
||||
|
||||
[*Note [4](#note-4)*:
|
||||
|
||||
In that case, the return type is deduced from return statements
|
||||
as described in [[dcl.spec.auto]](dcl.spec.auto "9.2.9.7 Placeholder type specifiers")[.](#5.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [3](#example-3)*: auto x1 = [](int i) { return i; }; // OK, return type is intauto x2 = []{ return { 1, 2 }; }; // error: deducing return type from [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]")int j;auto x3 = [&]()->auto&& { return j; }; // OK, return type is int& â *end example*]
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2183)
|
||||
|
||||
A lambda is a [*generic lambda*](#def:generic_lambda "7.5.6.1 General [expr.prim.lambda.general]") if the [*lambda-expression*](#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") has any generic parameter type placeholders ([[dcl.spec.auto]](dcl.spec.auto "9.2.9.7 Placeholder type specifiers")), or
|
||||
if the lambda has a [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]")[.](#6.sentence-1)
|
||||
|
||||
[*Example [4](#example-4)*: auto x = [](int i, auto a) { return i; }; // OK, a generic lambdaauto y = [](this auto self, int i) { return i; }; // OK, a generic lambdaauto z = []<class T>(int i) { return i; }; // OK, a generic lambda â *end example*]
|
||||
19
cppdraft/expr/prim/literal.md
Normal file
19
cppdraft/expr/prim/literal.md
Normal file
@@ -0,0 +1,19 @@
|
||||
[expr.prim.literal]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#literal)
|
||||
|
||||
### 7.5.2 Literals [expr.prim.literal]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1249)
|
||||
|
||||
The type of a [*literal*](lex.literal.kinds#nt:literal "5.13.1 Kinds of literals [lex.literal.kinds]") is determined based on its form as specified in [[lex.literal]](lex.literal "5.13 Literals")[.](#1.sentence-1)
|
||||
|
||||
A [*string-literal*](lex.string#nt:string-literal "5.13.5 String literals [lex.string]") is an lvalue
|
||||
designating a corresponding string literal object ([[lex.string]](lex.string "5.13.5 String literals")),
|
||||
a [*user-defined-literal*](lex.ext#nt:user-defined-literal "5.13.9 User-defined literals [lex.ext]") has the same value category
|
||||
as the corresponding operator call expression described in [[lex.ext]](lex.ext "5.13.9 User-defined literals"),
|
||||
and any other [*literal*](lex.literal.kinds#nt:literal "5.13.1 Kinds of literals [lex.literal.kinds]") is a prvalue[.](#1.sentence-2)
|
||||
43
cppdraft/expr/prim/pack/index.md
Normal file
43
cppdraft/expr/prim/pack/index.md
Normal file
@@ -0,0 +1,43 @@
|
||||
[expr.prim.pack.index]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#pack.index)
|
||||
|
||||
### 7.5.5 Names [[expr.prim.id]](expr.prim.id#expr.prim.pack.index)
|
||||
|
||||
#### 7.5.5.4 Pack indexing expression [expr.prim.pack.index]
|
||||
|
||||
[pack-index-expression:](#nt:pack-index-expression "7.5.5.4 Pack indexing expression [expr.prim.pack.index]")
|
||||
[*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") ... [ [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]") ]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2010)
|
||||
|
||||
The [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") P in a [*pack-index-expression*](#nt:pack-index-expression "7.5.5.4 Pack indexing expression [expr.prim.pack.index]") shall be an [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") that denotes a pack[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2014)
|
||||
|
||||
The [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]") shall be
|
||||
a converted constant expression ([[expr.const]](expr.const "7.7 Constant expressions")) of type std::size_t whose value V, termed the index,
|
||||
is such that 0â¤V<sizeof...(P)[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2020)
|
||||
|
||||
A [*pack-index-expression*](#nt:pack-index-expression "7.5.5.4 Pack indexing expression [expr.prim.pack.index]") is a pack expansion ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates"))[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L2023)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
A [*pack-index-expression*](#nt:pack-index-expression "7.5.5.4 Pack indexing expression [expr.prim.pack.index]") denotes
|
||||
the Vth element of the pack[.](#4.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
17
cppdraft/expr/prim/paren.md
Normal file
17
cppdraft/expr/prim/paren.md
Normal file
@@ -0,0 +1,17 @@
|
||||
[expr.prim.paren]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#paren)
|
||||
|
||||
### 7.5.4 Parentheses [expr.prim.paren]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1349)
|
||||
|
||||
A parenthesized expression (E) is a primary expression whose type, result, and value category are identical to those of E[.](#1.sentence-1)
|
||||
|
||||
The parenthesized expression can be used in exactly the same contexts as
|
||||
those where E can be used, and with the same
|
||||
meaning, except as otherwise indicated[.](#1.sentence-2)
|
||||
272
cppdraft/expr/prim/req.md
Normal file
272
cppdraft/expr/prim/req.md
Normal file
@@ -0,0 +1,272 @@
|
||||
[expr.prim.req]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#req)
|
||||
|
||||
### 7.5.8 Requires expressions [expr.prim.req]
|
||||
|
||||
#### [7.5.8.1](#general) General [[expr.prim.req.general]](expr.prim.req.general)
|
||||
|
||||
[1](#general-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3193)
|
||||
|
||||
A [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") provides a concise way to express
|
||||
requirements on template arguments
|
||||
that can be checked by [name lookup](basic.lookup "6.5 Name lookup [basic.lookup]") or by checking properties of types and expressions[.](#general-1.sentence-1)
|
||||
|
||||
[requires-expression:](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]")
|
||||
requires [*requirement-parameter-list*](#nt:requirement-parameter-list "7.5.8.1 General [expr.prim.req.general]")opt [*requirement-body*](#nt:requirement-body "7.5.8.1 General [expr.prim.req.general]")
|
||||
|
||||
[requirement-parameter-list:](#nt:requirement-parameter-list "7.5.8.1 General [expr.prim.req.general]")
|
||||
( [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") )
|
||||
|
||||
[requirement-body:](#nt:requirement-body "7.5.8.1 General [expr.prim.req.general]")
|
||||
{ [*requirement-seq*](#nt:requirement-seq "7.5.8.1 General [expr.prim.req.general]") }
|
||||
|
||||
[requirement-seq:](#nt:requirement-seq "7.5.8.1 General [expr.prim.req.general]")
|
||||
[*requirement*](#nt:requirement "7.5.8.1 General [expr.prim.req.general]") [*requirement-seq*](#nt:requirement-seq "7.5.8.1 General [expr.prim.req.general]")opt
|
||||
|
||||
[requirement:](#nt:requirement "7.5.8.1 General [expr.prim.req.general]")
|
||||
[*simple-requirement*](#nt:simple-requirement "7.5.8.2 Simple requirements [expr.prim.req.simple]")
|
||||
[*type-requirement*](#nt:type-requirement "7.5.8.3 Type requirements [expr.prim.req.type]")
|
||||
[*compound-requirement*](#nt:compound-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]")
|
||||
[*nested-requirement*](#nt:nested-requirement "7.5.8.5 Nested requirements [expr.prim.req.nested]")
|
||||
|
||||
[2](#general-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3228)
|
||||
|
||||
A [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") is a prvalue of type bool whose value is described below[.](#general-2.sentence-1)
|
||||
|
||||
[3](#general-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3232)
|
||||
|
||||
[*Example [1](#general-example-1)*:
|
||||
|
||||
A common use of [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]")*s* is to define
|
||||
requirements in concepts such as the one below:template<typename T>concept R = requires (T i) {typename T::type; {*i} -> std::[convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<const typename T::type&>; };
|
||||
|
||||
A [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") can also be used in a[*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") ([[temp.pre]](temp.pre "13.1 Preamble")) as a way of writing ad hoc
|
||||
constraints on template arguments such as the one below:template<typename T>requires requires (T x) { x + x; } T add(T a, T b) { return a + b; }
|
||||
|
||||
The first requires introduces the[*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]"), and the second
|
||||
introduces the [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]")[.](#general-3.sentence-3)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[4](#general-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3256)
|
||||
|
||||
A [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") may introduce local parameters using a[*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]")[.](#general-4.sentence-1)
|
||||
|
||||
A local parameter of a [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") shall not have a
|
||||
default argument[.](#general-4.sentence-2)
|
||||
|
||||
The type of such a parameter is determined as specified for
|
||||
a function parameter in [[dcl.fct]](dcl.fct "9.3.4.6 Functions")[.](#general-4.sentence-3)
|
||||
|
||||
These parameters have no linkage, storage, or lifetime; they are only used
|
||||
as notation for the purpose of defining [*requirement*](#nt:requirement "7.5.8.1 General [expr.prim.req.general]")*s*[.](#general-4.sentence-4)
|
||||
|
||||
The [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") of a[*requirement-parameter-list*](#nt:requirement-parameter-list "7.5.8.1 General [expr.prim.req.general]") shall not terminate with an ellipsis[.](#general-4.sentence-5)
|
||||
|
||||
[*Example [2](#general-example-2)*: template<typename T>concept C = requires(T t, ...) { // error: terminates with an ellipsis t;};template<typename T>concept C2 = requires(T p[2]) {(decltype(p))nullptr; // OK, p has type âpointer to T''}; â *end example*]
|
||||
|
||||
[5](#general-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3281)
|
||||
|
||||
The substitution of template arguments into a [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") can result in
|
||||
the formation of invalid types or expressions in the immediate context of
|
||||
its [*requirement*](#nt:requirement "7.5.8.1 General [expr.prim.req.general]")*s* ([[temp.deduct.general]](temp.deduct.general "13.10.3.1 General")) or
|
||||
the violation of the semantic constraints of those [*requirement*](#nt:requirement "7.5.8.1 General [expr.prim.req.general]")*s*[.](#general-5.sentence-1)
|
||||
|
||||
In such cases, the [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") evaluates to false;
|
||||
it does not cause the program to be ill-formed[.](#general-5.sentence-2)
|
||||
|
||||
The substitution and semantic constraint checking
|
||||
proceeds in lexical order and stops when a condition that
|
||||
determines the result of the [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") is encountered[.](#general-5.sentence-3)
|
||||
|
||||
If substitution (if any) and semantic constraint checking succeed,
|
||||
the [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") evaluates to true[.](#general-5.sentence-4)
|
||||
|
||||
[*Note [1](#general-note-1)*:
|
||||
|
||||
If a [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") contains invalid types or expressions in
|
||||
its [*requirement*](#nt:requirement "7.5.8.1 General [expr.prim.req.general]")*s*, and it does not appear within the declaration of a templated
|
||||
entity, then the program is ill-formed[.](#general-5.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
If the substitution of template arguments into a [*requirement*](#nt:requirement "7.5.8.1 General [expr.prim.req.general]") would always result in a substitution failure, the program is ill-formed;
|
||||
no diagnostic required[.](#general-5.sentence-6)
|
||||
|
||||
[*Example [3](#general-example-3)*: template<typename T> concept C =requires {new decltype((void)T{}); // ill-formed, no diagnostic required}; â *end example*]
|
||||
|
||||
#### [7.5.8.2](#simple) Simple requirements [[expr.prim.req.simple]](expr.prim.req.simple)
|
||||
|
||||
[simple-requirement:](#nt:simple-requirement "7.5.8.2 Simple requirements [expr.prim.req.simple]")
|
||||
[*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") ;
|
||||
|
||||
[1](#simple-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3319)
|
||||
|
||||
A [*simple-requirement*](#nt:simple-requirement "7.5.8.2 Simple requirements [expr.prim.req.simple]") asserts
|
||||
the validity of an [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]")[.](#simple-1.sentence-1)
|
||||
|
||||
The [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") is an unevaluated operand[.](#simple-1.sentence-2)
|
||||
|
||||
[*Note [1](#simple-note-1)*:
|
||||
|
||||
The enclosing [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") will evaluate to false if substitution of template arguments into the [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") fails[.](#simple-1.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [1](#simple-example-1)*: template<typename T> concept C =requires (T a, T b) { a + b; // C<T> is true if a + b is a valid expression}; â *end example*]
|
||||
|
||||
[2](#simple-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3336)
|
||||
|
||||
A [*requirement*](#nt:requirement "7.5.8.1 General [expr.prim.req.general]") that starts with a requires token
|
||||
is never interpreted as a [*simple-requirement*](#nt:simple-requirement "7.5.8.2 Simple requirements [expr.prim.req.simple]")[.](#simple-2.sentence-1)
|
||||
|
||||
[*Note [2](#simple-note-2)*:
|
||||
|
||||
This simplifies distinguishing between a [*simple-requirement*](#nt:simple-requirement "7.5.8.2 Simple requirements [expr.prim.req.simple]") and a [*nested-requirement*](#nt:nested-requirement "7.5.8.5 Nested requirements [expr.prim.req.nested]")[.](#simple-2.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
#### [7.5.8.3](#type) Type requirements [[expr.prim.req.type]](expr.prim.req.type)
|
||||
|
||||
[type-requirement:](#nt:type-requirement "7.5.8.3 Type requirements [expr.prim.req.type]")
|
||||
typename [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")opt [*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]") ;
|
||||
typename [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]")
|
||||
typename [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]")
|
||||
|
||||
[1](#type-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3354)
|
||||
|
||||
A [*type-requirement*](#nt:type-requirement "7.5.8.3 Type requirements [expr.prim.req.type]") asserts the validity of a type[.](#type-1.sentence-1)
|
||||
|
||||
The component names of a [*type-requirement*](#nt:type-requirement "7.5.8.3 Type requirements [expr.prim.req.type]") 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[*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]") (if any)[.](#type-1.sentence-2)
|
||||
|
||||
[*Note [1](#type-note-1)*:
|
||||
|
||||
The enclosing [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") will evaluate to false if substitution of template arguments fails[.](#type-1.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [1](#type-example-1)*: template<typename T, typename T::type = 0> struct S;template<typename T> using Ref = T&;
|
||||
|
||||
template<typename T> concept C = requires {typename T::inner; // required nested member nametypename S<T>; // required valid ([[temp.names]](temp.names "13.3 Names of template specializations")) [*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]"); fails if T::type does not exist as a type// to which 0 can be implicitly convertedtypename Ref<T>; // required alias template substitution, fails if T is voidtypename [:T::r1:]; // fails if T::r1 is not a reflection of a typetypename [:T::r2:]<int>; // fails if T::r2 is not a reflection of a template Z for which Z<int> is a type}; â *end example*]
|
||||
|
||||
[2](#type-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3379)
|
||||
|
||||
A [*type-requirement*](#nt:type-requirement "7.5.8.3 Type requirements [expr.prim.req.type]") that names a class template specialization
|
||||
does not require that type to be complete ([[basic.types.general]](basic.types.general#term.incomplete.type "6.9.1 General"))[.](#type-2.sentence-1)
|
||||
|
||||
#### [7.5.8.4](#compound) Compound requirements [[expr.prim.req.compound]](expr.prim.req.compound)
|
||||
|
||||
[compound-requirement:](#nt:compound-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]")
|
||||
{ [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") } noexceptopt [*return-type-requirement*](#nt:return-type-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]")opt ;
|
||||
|
||||
[return-type-requirement:](#nt:return-type-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]")
|
||||
-> [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]")
|
||||
|
||||
[1](#compound-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3396)
|
||||
|
||||
A [*compound-requirement*](#nt:compound-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]") asserts properties
|
||||
of the [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") E[.](#compound-1.sentence-1)
|
||||
|
||||
The [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") is an unevaluated operand[.](#compound-1.sentence-2)
|
||||
|
||||
Substitution
|
||||
of template arguments (if any) and verification of
|
||||
semantic properties proceed in the following order:
|
||||
|
||||
- [(1.1)](#compound-1.1)
|
||||
|
||||
Substitution of template arguments (if any)
|
||||
into the [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") is performed[.](#compound-1.1.sentence-1)
|
||||
|
||||
- [(1.2)](#compound-1.2)
|
||||
|
||||
If the noexcept specifier is present,E shall not be a potentially-throwing expression ([[except.spec]](except.spec "14.5 Exception specifications"))[.](#compound-1.2.sentence-1)
|
||||
|
||||
- [(1.3)](#compound-1.3)
|
||||
|
||||
If the [*return-type-requirement*](#nt:return-type-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]") is present, then:
|
||||
* [(1.3.1)](#compound-1.3.1)
|
||||
|
||||
Substitution of template arguments (if any)
|
||||
into the [*return-type-requirement*](#nt:return-type-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]") is performed[.](#compound-1.3.1.sentence-1)
|
||||
|
||||
* [(1.3.2)](#compound-1.3.2)
|
||||
|
||||
The immediately-declared constraint ([[temp.param]](temp.param "13.2 Template parameters"))
|
||||
of the [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]") for decltype((E)) shall be satisfied[.](#compound-1.3.2.sentence-1)
|
||||
|
||||
[*Example [1](#compound-example-1)*:
|
||||
Given concepts C and D,requires {{ E1 } -> C; { E2 } -> D<A1, â¯, An>;}; is equivalent torequires { E1; requires C<decltype((E1))>;
|
||||
E2; requires D<decltype((E2)), A1, â¯, An>;}; (including in the case where n is zero)[.](#compound-1.3.sentence-2)
|
||||
â *end example*]
|
||||
|
||||
[2](#compound-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3442)
|
||||
|
||||
[*Example [2](#compound-example-2)*: template<typename T> concept C1 = requires(T x) {{x++};};
|
||||
|
||||
The [*compound-requirement*](#nt:compound-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]") in C1 requires that x++ is a valid expression[.](#compound-2.sentence-1)
|
||||
|
||||
It is equivalent to the [*simple-requirement*](#nt:simple-requirement "7.5.8.2 Simple requirements [expr.prim.req.simple]")x++;[.](#compound-2.sentence-2)
|
||||
|
||||
template<typename T> concept C2 = requires(T x) {{*x} -> std::[same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<typename T::inner>;};
|
||||
|
||||
The [*compound-requirement*](#nt:compound-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]") in C2 requires that *x is a valid expression,
|
||||
that typename T::inner is a valid type, and
|
||||
that std::[same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<decltype((*x)), typename T::inner> is satisfied[.](#compound-2.sentence-3)
|
||||
|
||||
template<typename T> concept C3 =requires(T x) {{g(x)} noexcept; };
|
||||
|
||||
The [*compound-requirement*](#nt:compound-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]") in C3 requires that g(x) is a valid expression and
|
||||
that g(x) is non-throwing[.](#compound-2.sentence-4)
|
||||
|
||||
â *end example*]
|
||||
|
||||
#### [7.5.8.5](#nested) Nested requirements [[expr.prim.req.nested]](expr.prim.req.nested)
|
||||
|
||||
[nested-requirement:](#nt:nested-requirement "7.5.8.5 Nested requirements [expr.prim.req.nested]")
|
||||
requires [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") ;
|
||||
|
||||
[1](#nested-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3485)
|
||||
|
||||
A [*nested-requirement*](#nt:nested-requirement "7.5.8.5 Nested requirements [expr.prim.req.nested]") can be used
|
||||
to specify additional constraints in terms of local parameters[.](#nested-1.sentence-1)
|
||||
|
||||
The [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") shall be satisfied ([[temp.constr.decl]](temp.constr.decl "13.5.3 Constrained declarations"))
|
||||
by the substituted template arguments, if any[.](#nested-1.sentence-2)
|
||||
|
||||
Substitution of template arguments into a [*nested-requirement*](#nt:nested-requirement "7.5.8.5 Nested requirements [expr.prim.req.nested]") does not result in substitution into the [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") other than as specified in [[temp.constr.constr]](temp.constr.constr "13.5.2 Constraints")[.](#nested-1.sentence-3)
|
||||
|
||||
[*Example [1](#nested-example-1)*:
|
||||
|
||||
template<typename U> concept C = sizeof(U) == 1;
|
||||
|
||||
template<typename T> concept D = requires (T t) {requires C<decltype (+t)>;};D<T> is satisfied if sizeof(decltype (+t)) == 1 ([[temp.constr.atomic]](temp.constr.atomic "13.5.2.3 Atomic constraints"))[.](#nested-1.sentence-4)
|
||||
|
||||
â *end example*]
|
||||
78
cppdraft/expr/prim/req/compound.md
Normal file
78
cppdraft/expr/prim/req/compound.md
Normal file
@@ -0,0 +1,78 @@
|
||||
[expr.prim.req.compound]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#req.compound)
|
||||
|
||||
### 7.5.8 Requires expressions [[expr.prim.req]](expr.prim.req#compound)
|
||||
|
||||
#### 7.5.8.4 Compound requirements [expr.prim.req.compound]
|
||||
|
||||
[compound-requirement:](#nt:compound-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]")
|
||||
{ [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") } noexceptopt [*return-type-requirement*](#nt:return-type-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]")opt ;
|
||||
|
||||
[return-type-requirement:](#nt:return-type-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]")
|
||||
-> [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]")
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3396)
|
||||
|
||||
A [*compound-requirement*](#nt:compound-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]") asserts properties
|
||||
of the [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") E[.](#1.sentence-1)
|
||||
|
||||
The [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") is an unevaluated operand[.](#1.sentence-2)
|
||||
|
||||
Substitution
|
||||
of template arguments (if any) and verification of
|
||||
semantic properties proceed in the following order:
|
||||
|
||||
- [(1.1)](#1.1)
|
||||
|
||||
Substitution of template arguments (if any)
|
||||
into the [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") is performed[.](#1.1.sentence-1)
|
||||
|
||||
- [(1.2)](#1.2)
|
||||
|
||||
If the noexcept specifier is present,E shall not be a potentially-throwing expression ([[except.spec]](except.spec "14.5 Exception specifications"))[.](#1.2.sentence-1)
|
||||
|
||||
- [(1.3)](#1.3)
|
||||
|
||||
If the [*return-type-requirement*](#nt:return-type-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]") is present, then:
|
||||
* [(1.3.1)](#1.3.1)
|
||||
|
||||
Substitution of template arguments (if any)
|
||||
into the [*return-type-requirement*](#nt:return-type-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]") is performed[.](#1.3.1.sentence-1)
|
||||
|
||||
* [(1.3.2)](#1.3.2)
|
||||
|
||||
The immediately-declared constraint ([[temp.param]](temp.param "13.2 Template parameters"))
|
||||
of the [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]") for decltype((E)) shall be satisfied[.](#1.3.2.sentence-1)
|
||||
|
||||
[*Example [1](#example-1)*:
|
||||
Given concepts C and D,requires {{ E1 } -> C; { E2 } -> D<A1, â¯, An>;}; is equivalent torequires { E1; requires C<decltype((E1))>;
|
||||
E2; requires D<decltype((E2)), A1, â¯, An>;}; (including in the case where n is zero)[.](#1.3.sentence-2)
|
||||
â *end example*]
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3442)
|
||||
|
||||
[*Example [2](#example-2)*: template<typename T> concept C1 = requires(T x) {{x++};};
|
||||
|
||||
The [*compound-requirement*](#nt:compound-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]") in C1 requires that x++ is a valid expression[.](#2.sentence-1)
|
||||
|
||||
It is equivalent to the [*simple-requirement*](expr.prim.req.simple#nt:simple-requirement "7.5.8.2 Simple requirements [expr.prim.req.simple]")x++;[.](#2.sentence-2)
|
||||
|
||||
template<typename T> concept C2 = requires(T x) {{*x} -> std::[same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<typename T::inner>;};
|
||||
|
||||
The [*compound-requirement*](#nt:compound-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]") in C2 requires that *x is a valid expression,
|
||||
that typename T::inner is a valid type, and
|
||||
that std::[same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<decltype((*x)), typename T::inner> is satisfied[.](#2.sentence-3)
|
||||
|
||||
template<typename T> concept C3 =requires(T x) {{g(x)} noexcept; };
|
||||
|
||||
The [*compound-requirement*](#nt:compound-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]") in C3 requires that g(x) is a valid expression and
|
||||
that g(x) is non-throwing[.](#2.sentence-4)
|
||||
|
||||
â *end example*]
|
||||
109
cppdraft/expr/prim/req/general.md
Normal file
109
cppdraft/expr/prim/req/general.md
Normal file
@@ -0,0 +1,109 @@
|
||||
[expr.prim.req.general]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#req.general)
|
||||
|
||||
### 7.5.8 Requires expressions [[expr.prim.req]](expr.prim.req#general)
|
||||
|
||||
#### 7.5.8.1 General [expr.prim.req.general]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3193)
|
||||
|
||||
A [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") provides a concise way to express
|
||||
requirements on template arguments
|
||||
that can be checked by [name lookup](basic.lookup "6.5 Name lookup [basic.lookup]") or by checking properties of types and expressions[.](#1.sentence-1)
|
||||
|
||||
[requires-expression:](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]")
|
||||
requires [*requirement-parameter-list*](#nt:requirement-parameter-list "7.5.8.1 General [expr.prim.req.general]")opt [*requirement-body*](#nt:requirement-body "7.5.8.1 General [expr.prim.req.general]")
|
||||
|
||||
[requirement-parameter-list:](#nt:requirement-parameter-list "7.5.8.1 General [expr.prim.req.general]")
|
||||
( [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") )
|
||||
|
||||
[requirement-body:](#nt:requirement-body "7.5.8.1 General [expr.prim.req.general]")
|
||||
{ [*requirement-seq*](#nt:requirement-seq "7.5.8.1 General [expr.prim.req.general]") }
|
||||
|
||||
[requirement-seq:](#nt:requirement-seq "7.5.8.1 General [expr.prim.req.general]")
|
||||
[*requirement*](#nt:requirement "7.5.8.1 General [expr.prim.req.general]") [*requirement-seq*](#nt:requirement-seq "7.5.8.1 General [expr.prim.req.general]")opt
|
||||
|
||||
[requirement:](#nt:requirement "7.5.8.1 General [expr.prim.req.general]")
|
||||
[*simple-requirement*](expr.prim.req.simple#nt:simple-requirement "7.5.8.2 Simple requirements [expr.prim.req.simple]")
|
||||
[*type-requirement*](expr.prim.req.type#nt:type-requirement "7.5.8.3 Type requirements [expr.prim.req.type]")
|
||||
[*compound-requirement*](expr.prim.req.compound#nt:compound-requirement "7.5.8.4 Compound requirements [expr.prim.req.compound]")
|
||||
[*nested-requirement*](expr.prim.req.nested#nt:nested-requirement "7.5.8.5 Nested requirements [expr.prim.req.nested]")
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3228)
|
||||
|
||||
A [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") is a prvalue of type bool whose value is described below[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3232)
|
||||
|
||||
[*Example [1](#example-1)*:
|
||||
|
||||
A common use of [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]")*s* is to define
|
||||
requirements in concepts such as the one below:template<typename T>concept R = requires (T i) {typename T::type; {*i} -> std::[convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<const typename T::type&>; };
|
||||
|
||||
A [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") can also be used in a[*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") ([[temp.pre]](temp.pre "13.1 Preamble")) as a way of writing ad hoc
|
||||
constraints on template arguments such as the one below:template<typename T>requires requires (T x) { x + x; } T add(T a, T b) { return a + b; }
|
||||
|
||||
The first requires introduces the[*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]"), and the second
|
||||
introduces the [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]")[.](#3.sentence-3)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3256)
|
||||
|
||||
A [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") may introduce local parameters using a[*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]")[.](#4.sentence-1)
|
||||
|
||||
A local parameter of a [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") shall not have a
|
||||
default argument[.](#4.sentence-2)
|
||||
|
||||
The type of such a parameter is determined as specified for
|
||||
a function parameter in [[dcl.fct]](dcl.fct "9.3.4.6 Functions")[.](#4.sentence-3)
|
||||
|
||||
These parameters have no linkage, storage, or lifetime; they are only used
|
||||
as notation for the purpose of defining [*requirement*](#nt:requirement "7.5.8.1 General [expr.prim.req.general]")*s*[.](#4.sentence-4)
|
||||
|
||||
The [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") of a[*requirement-parameter-list*](#nt:requirement-parameter-list "7.5.8.1 General [expr.prim.req.general]") shall not terminate with an ellipsis[.](#4.sentence-5)
|
||||
|
||||
[*Example [2](#example-2)*: template<typename T>concept C = requires(T t, ...) { // error: terminates with an ellipsis t;};template<typename T>concept C2 = requires(T p[2]) {(decltype(p))nullptr; // OK, p has type âpointer to T''}; â *end example*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3281)
|
||||
|
||||
The substitution of template arguments into a [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") can result in
|
||||
the formation of invalid types or expressions in the immediate context of
|
||||
its [*requirement*](#nt:requirement "7.5.8.1 General [expr.prim.req.general]")*s* ([[temp.deduct.general]](temp.deduct.general "13.10.3.1 General")) or
|
||||
the violation of the semantic constraints of those [*requirement*](#nt:requirement "7.5.8.1 General [expr.prim.req.general]")*s*[.](#5.sentence-1)
|
||||
|
||||
In such cases, the [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") evaluates to false;
|
||||
it does not cause the program to be ill-formed[.](#5.sentence-2)
|
||||
|
||||
The substitution and semantic constraint checking
|
||||
proceeds in lexical order and stops when a condition that
|
||||
determines the result of the [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") is encountered[.](#5.sentence-3)
|
||||
|
||||
If substitution (if any) and semantic constraint checking succeed,
|
||||
the [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") evaluates to true[.](#5.sentence-4)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
If a [*requires-expression*](#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") contains invalid types or expressions in
|
||||
its [*requirement*](#nt:requirement "7.5.8.1 General [expr.prim.req.general]")*s*, and it does not appear within the declaration of a templated
|
||||
entity, then the program is ill-formed[.](#5.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
If the substitution of template arguments into a [*requirement*](#nt:requirement "7.5.8.1 General [expr.prim.req.general]") would always result in a substitution failure, the program is ill-formed;
|
||||
no diagnostic required[.](#5.sentence-6)
|
||||
|
||||
[*Example [3](#example-3)*: template<typename T> concept C =requires {new decltype((void)T{}); // ill-formed, no diagnostic required}; â *end example*]
|
||||
32
cppdraft/expr/prim/req/nested.md
Normal file
32
cppdraft/expr/prim/req/nested.md
Normal file
@@ -0,0 +1,32 @@
|
||||
[expr.prim.req.nested]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#req.nested)
|
||||
|
||||
### 7.5.8 Requires expressions [[expr.prim.req]](expr.prim.req#nested)
|
||||
|
||||
#### 7.5.8.5 Nested requirements [expr.prim.req.nested]
|
||||
|
||||
[nested-requirement:](#nt:nested-requirement "7.5.8.5 Nested requirements [expr.prim.req.nested]")
|
||||
requires [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") ;
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3485)
|
||||
|
||||
A [*nested-requirement*](#nt:nested-requirement "7.5.8.5 Nested requirements [expr.prim.req.nested]") can be used
|
||||
to specify additional constraints in terms of local parameters[.](#1.sentence-1)
|
||||
|
||||
The [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") shall be satisfied ([[temp.constr.decl]](temp.constr.decl "13.5.3 Constrained declarations"))
|
||||
by the substituted template arguments, if any[.](#1.sentence-2)
|
||||
|
||||
Substitution of template arguments into a [*nested-requirement*](#nt:nested-requirement "7.5.8.5 Nested requirements [expr.prim.req.nested]") does not result in substitution into the [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") other than as specified in [[temp.constr.constr]](temp.constr.constr "13.5.2 Constraints")[.](#1.sentence-3)
|
||||
|
||||
[*Example [1](#example-1)*:
|
||||
|
||||
template<typename U> concept C = sizeof(U) == 1;
|
||||
|
||||
template<typename T> concept D = requires (T t) {requires C<decltype (+t)>;};D<T> is satisfied if sizeof(decltype (+t)) == 1 ([[temp.constr.atomic]](temp.constr.atomic "13.5.2.3 Atomic constraints"))[.](#1.sentence-4)
|
||||
|
||||
â *end example*]
|
||||
42
cppdraft/expr/prim/req/simple.md
Normal file
42
cppdraft/expr/prim/req/simple.md
Normal file
@@ -0,0 +1,42 @@
|
||||
[expr.prim.req.simple]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#req.simple)
|
||||
|
||||
### 7.5.8 Requires expressions [[expr.prim.req]](expr.prim.req#simple)
|
||||
|
||||
#### 7.5.8.2 Simple requirements [expr.prim.req.simple]
|
||||
|
||||
[simple-requirement:](#nt:simple-requirement "7.5.8.2 Simple requirements [expr.prim.req.simple]")
|
||||
[*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") ;
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3319)
|
||||
|
||||
A [*simple-requirement*](#nt:simple-requirement "7.5.8.2 Simple requirements [expr.prim.req.simple]") asserts
|
||||
the validity of an [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]")[.](#1.sentence-1)
|
||||
|
||||
The [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") is an unevaluated operand[.](#1.sentence-2)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
The enclosing [*requires-expression*](expr.prim.req.general#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") will evaluate to false if substitution of template arguments into the [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") fails[.](#1.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [1](#example-1)*: template<typename T> concept C =requires (T a, T b) { a + b; // C<T> is true if a + b is a valid expression}; â *end example*]
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3336)
|
||||
|
||||
A [*requirement*](expr.prim.req.general#nt:requirement "7.5.8.1 General [expr.prim.req.general]") that starts with a requires token
|
||||
is never interpreted as a [*simple-requirement*](#nt:simple-requirement "7.5.8.2 Simple requirements [expr.prim.req.simple]")[.](#2.sentence-1)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
This simplifies distinguishing between a [*simple-requirement*](#nt:simple-requirement "7.5.8.2 Simple requirements [expr.prim.req.simple]") and a [*nested-requirement*](expr.prim.req.nested#nt:nested-requirement "7.5.8.5 Nested requirements [expr.prim.req.nested]")[.](#2.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
39
cppdraft/expr/prim/req/type.md
Normal file
39
cppdraft/expr/prim/req/type.md
Normal file
@@ -0,0 +1,39 @@
|
||||
[expr.prim.req.type]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#req.type)
|
||||
|
||||
### 7.5.8 Requires expressions [[expr.prim.req]](expr.prim.req#type)
|
||||
|
||||
#### 7.5.8.3 Type requirements [expr.prim.req.type]
|
||||
|
||||
[type-requirement:](#nt:type-requirement "7.5.8.3 Type requirements [expr.prim.req.type]")
|
||||
typename [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")opt [*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]") ;
|
||||
typename [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]")
|
||||
typename [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]")
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3354)
|
||||
|
||||
A [*type-requirement*](#nt:type-requirement "7.5.8.3 Type requirements [expr.prim.req.type]") asserts the validity of a type[.](#1.sentence-1)
|
||||
|
||||
The component names of a [*type-requirement*](#nt:type-requirement "7.5.8.3 Type requirements [expr.prim.req.type]") 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[*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]") (if any)[.](#1.sentence-2)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
The enclosing [*requires-expression*](expr.prim.req.general#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") will evaluate to false if substitution of template arguments fails[.](#1.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [1](#example-1)*: template<typename T, typename T::type = 0> struct S;template<typename T> using Ref = T&;
|
||||
|
||||
template<typename T> concept C = requires {typename T::inner; // required nested member nametypename S<T>; // required valid ([[temp.names]](temp.names "13.3 Names of template specializations")) [*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]"); fails if T::type does not exist as a type// to which 0 can be implicitly convertedtypename Ref<T>; // required alias template substitution, fails if T is voidtypename [:T::r1:]; // fails if T::r1 is not a reflection of a typetypename [:T::r2:]<int>; // fails if T::r2 is not a reflection of a template Z for which Z<int> is a type}; â *end example*]
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3379)
|
||||
|
||||
A [*type-requirement*](#nt:type-requirement "7.5.8.3 Type requirements [expr.prim.req.type]") that names a class template specialization
|
||||
does not require that type to be complete ([[basic.types.general]](basic.types.general#term.incomplete.type "6.9.1 General"))[.](#2.sentence-1)
|
||||
163
cppdraft/expr/prim/splice.md
Normal file
163
cppdraft/expr/prim/splice.md
Normal file
@@ -0,0 +1,163 @@
|
||||
[expr.prim.splice]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#splice)
|
||||
|
||||
### 7.5.9 Expression splicing [expr.prim.splice]
|
||||
|
||||
[splice-expression:](#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]")
|
||||
[*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]")
|
||||
template [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]")
|
||||
template [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]")
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3516)
|
||||
|
||||
A [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]") or [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]") immediately followed by :: or preceded by typename is never interpreted as part of a [*splice-expression*](#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]")[.](#1.sentence-1)
|
||||
|
||||
[*Example [1](#example-1)*: struct S { static constexpr int a = 1; };template<typename> struct TCls { static constexpr int b = 2; };
|
||||
|
||||
constexpr int c = [:^^S:]::a; // OK, [:^^S:] is not an expressionconstexpr int d = template [:^^TCls:]<int>::b; // OK, template [:^^TCls:]<int> is not an expressiontemplate<auto V> constexpr int e = [:V:]; // OKconstexpr int f = template [:^^e:]<^^S::a>; // OKconstexpr auto g = typename [:^^int:](42); // OK, typename [:^^int:] is a [*splice-type-specifier*](dcl.type.splice#nt:splice-type-specifier "9.2.9.9 Type splicing [dcl.type.splice]")constexpr auto h = ^^g;constexpr auto i = e<[:^^h:]>; // error: unparenthesized [*splice-expression*](#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") used as template argumentconstexpr auto j = e<([:^^h:])>; // OK â *end example*]
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3539)
|
||||
|
||||
For a [*splice-expression*](#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") of the form [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]"),
|
||||
let S be the construct designated by [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]")[.](#2.sentence-1)
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
The expression is ill-formed if S is
|
||||
* [(2.1.1)](#2.1.1)
|
||||
|
||||
a constructor,
|
||||
|
||||
* [(2.1.2)](#2.1.2)
|
||||
|
||||
a destructor,
|
||||
|
||||
* [(2.1.3)](#2.1.3)
|
||||
|
||||
an unnamed bit-field, or
|
||||
|
||||
* [(2.1.4)](#2.1.4)
|
||||
|
||||
a local entity ([[basic.pre]](basic.pre "6.1 Preamble")) such that
|
||||
+
|
||||
[(2.1.4.1)](#2.1.4.1)
|
||||
there is a lambda scope that intervenes
|
||||
between the expression and the point at which S was introduced and
|
||||
|
||||
+
|
||||
[(2.1.4.2)](#2.1.4.2)
|
||||
the expression would be potentially evaluated
|
||||
if the effect of any enclosing typeid expressions ([[expr.typeid]](expr.typeid "7.6.1.8 Type identification"))
|
||||
were ignored[.](#2.1.sentence-1)
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
Otherwise, if S is a function F,
|
||||
the expression denotes an overload set containing all declarations of F that precede either the expression or
|
||||
the point immediately following the [*class-specifier*](class.pre#nt:class-specifier "11.1 Preamble [class.pre]") of
|
||||
the outermost class for which the expression is in a complete-class context;
|
||||
overload resolution is performed ([[over.match]](over.match "12.2 Overload resolution"), [[over.over]](over.over "12.3 Address of an overload set"))[.](#2.2.sentence-1)
|
||||
|
||||
- [(2.3)](#2.3)
|
||||
|
||||
Otherwise, if S is an object or a non-static data member,
|
||||
the expression is an lvalue designating S[.](#2.3.sentence-1)
|
||||
The expression has the same type as that of S, and
|
||||
is a bit-field if and only if S is a bit-field[.](#2.3.sentence-2)
|
||||
[*Note [1](#note-1)*:
|
||||
The implicit transformation
|
||||
whereby an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") denoting a non-static member
|
||||
becomes a class member access ([[expr.prim.id]](expr.prim.id "7.5.5 Names"))
|
||||
does not apply to a [*splice-expression*](#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]")[.](#2.3.sentence-3)
|
||||
â *end note*]
|
||||
|
||||
- [(2.4)](#2.4)
|
||||
|
||||
Otherwise, if S is a variable or a structured binding,S shall either have static or thread storage duration or
|
||||
shall inhabit a scope enclosing the expression[.](#2.4.sentence-1)
|
||||
The expression is an lvalue referring to the object or function X associated with or referenced by S,
|
||||
has the same type as that of S, and
|
||||
is a bit-field if and only if X is a bit-field[.](#2.4.sentence-2)
|
||||
[*Note [2](#note-2)*:
|
||||
The type of a [*splice-expression*](#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") designating a variable or structured binding of reference type
|
||||
will be adjusted to a non-reference type ([[expr.type]](expr.type "7.2.2 Type"))[.](#2.4.sentence-3)
|
||||
â *end note*]
|
||||
|
||||
- [(2.5)](#2.5)
|
||||
|
||||
Otherwise, if S is a value or an enumerator,
|
||||
the expression is a prvalue that computes S and
|
||||
whose type is the same as that of S[.](#2.5.sentence-1)
|
||||
|
||||
- [(2.6)](#2.6)
|
||||
|
||||
Otherwise, the expression is ill-formed[.](#2.6.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3603)
|
||||
|
||||
For a [*splice-expression*](#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") of
|
||||
the form template [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]"),
|
||||
the [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]") shall designate a function template T that is not a constructor template[.](#3.sentence-1)
|
||||
|
||||
The expression denotes an overload set containing all declarations of T that precede either the expression or
|
||||
the point immediately following the [*class-specifier*](class.pre#nt:class-specifier "11.1 Preamble [class.pre]") of
|
||||
the outermost class for which the expression is in a complete-class context;
|
||||
overload resolution is performed[.](#3.sentence-2)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
During overload resolution,
|
||||
candidate function templates undergo template argument deduction and
|
||||
the resulting specializations are considered as candidate functions[.](#3.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3619)
|
||||
|
||||
For a [*splice-expression*](#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") of
|
||||
the form template [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]"),
|
||||
the [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]") of
|
||||
the [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]") shall designate a template T[.](#4.sentence-1)
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
If T is a function template,
|
||||
the expression denotes an overload set containing all declarations of T that precede either the expression or
|
||||
the point immediately following the [*class-specifier*](class.pre#nt:class-specifier "11.1 Preamble [class.pre]") of
|
||||
the outermost class for which the expression is in a complete-class context;
|
||||
overload resolution is performed ([[over.match]](over.match "12.2 Overload resolution"), [[over.over]](over.over "12.3 Address of an overload set"))[.](#4.1.sentence-1)
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
Otherwise, if T is a variable template,
|
||||
let S be the specialization of T corresponding to
|
||||
the template argument list of the [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]")[.](#4.2.sentence-1)
|
||||
The expression is an lvalue referring to
|
||||
the object associated with S and has the same type as that of S[.](#4.2.sentence-2)
|
||||
|
||||
- [(4.3)](#4.3)
|
||||
|
||||
Otherwise, the expression is ill-formed[.](#4.3.sentence-1)
|
||||
|
||||
[*Note [4](#note-4)*:
|
||||
|
||||
Class members are accessible from any point
|
||||
when designated by [*splice-expression*](#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]")*s* ([[class.access.base]](class.access.base "11.8.3 Accessibility of base classes and base class members"))[.](#4.sentence-2)
|
||||
|
||||
A class member access expression ([[expr.ref]](expr.ref "7.6.1.5 Class member access"))
|
||||
whose right operand is a [*splice-expression*](#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") is ill-formed
|
||||
if the left operand (considered as a pointer) cannot be implicitly converted
|
||||
to a pointer to the designating class of the right operand[.](#4.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
92
cppdraft/expr/prim/this.md
Normal file
92
cppdraft/expr/prim/this.md
Normal file
@@ -0,0 +1,92 @@
|
||||
[expr.prim.this]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.5 Primary expressions [[expr.prim]](expr.prim#this)
|
||||
|
||||
### 7.5.3 This [expr.prim.this]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1263)
|
||||
|
||||
The keyword this names a pointer to the object for which an implicit object member
|
||||
function ([[class.mfct.non.static]](class.mfct.non.static "11.4.3 Non-static member functions")) is invoked or a non-static data member's
|
||||
initializer ([[class.mem]](class.mem "11.4 Class members")) is evaluated[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1269)
|
||||
|
||||
The [*current class*](#def:class,current "7.5.3 This [expr.prim.this]") at a program point is
|
||||
the class associated with the innermost class scope containing that point[.](#2.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
A [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") does not introduce a class scope[.](#2.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1276)
|
||||
|
||||
If the expression this appears within the predicate of a contract assertion ([[basic.contract.general]](basic.contract.general "6.11.1 General"))
|
||||
(including as the result of an implicit transformation ([[expr.prim.id.general]](expr.prim.id.general "7.5.5.1 General"))
|
||||
and including in the bodies of nested [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")*s*)
|
||||
and the current class
|
||||
encloses the contract assertion,const is combined with the [*cv-qualifier-seq*](dcl.decl.general#nt:cv-qualifier-seq "9.3.1 General [dcl.decl.general]") used to generate the resulting type (see below)[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1286)
|
||||
|
||||
If a declaration declares a member function or member function template of a
|
||||
class X, the expression this is a prvalue of type âpointer to[*cv-qualifier-seq*](dcl.decl.general#nt:cv-qualifier-seq "9.3.1 General [dcl.decl.general]") Xâ
|
||||
wherever X is the current class
|
||||
between the optional[*cv-qualifier-seq*](dcl.decl.general#nt:cv-qualifier-seq "9.3.1 General [dcl.decl.general]") and the end of the [*function-definition*](dcl.fct.def.general#nt:function-definition "9.6.1 General [dcl.fct.def.general]"),[*member-declarator*](class.mem.general#nt:member-declarator "11.4.1 General [class.mem.general]"), or [*declarator*](dcl.decl.general#nt:declarator "9.3.1 General [dcl.decl.general]")[.](#4.sentence-1)
|
||||
|
||||
It shall not appear within
|
||||
the declaration of
|
||||
a static or explicit object member function
|
||||
of the current class (although its type and value category
|
||||
are defined within such member functions as they are within an implicit object
|
||||
member function)[.](#4.sentence-2)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
This is because declaration matching does not
|
||||
occur until the complete declarator is known[.](#4.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
In a [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]"),
|
||||
the class being defined is not required to be complete
|
||||
for purposes of [class member access](expr.ref "7.6.1.5 Class member access [expr.ref]")[.](#4.sentence-4)
|
||||
|
||||
Class members declared later are not visible[.](#4.sentence-5)
|
||||
|
||||
[*Example [1](#example-1)*: struct A {char g(); template<class T> auto f(T t) -> decltype(t + g()){ return t + g(); }};template auto A::f(int t) -> decltype(t + g()); â *end example*]
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1320)
|
||||
|
||||
Otherwise, if a [*member-declarator*](class.mem.general#nt:member-declarator "11.4.1 General [class.mem.general]") declares a non-static data
|
||||
member ([[class.mem]](class.mem "11.4 Class members")) of a class X, the expression this is
|
||||
a prvalue of type âpointer to Xâ
|
||||
wherever X is the current class
|
||||
within the
|
||||
optional default member initializer ([[class.mem]](class.mem "11.4 Class members"))[.](#5.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L1328)
|
||||
|
||||
The expression this shall not appear in any other context[.](#6.sentence-1)
|
||||
|
||||
[*Example [2](#example-2)*: class Outer {int a[sizeof(*this)]; // error: not inside a member functionunsigned int sz = sizeof(*this); // OK, in default member initializervoid f() {int b[sizeof(*this)]; // OKstruct Inner {int c[sizeof(*this)]; // error: not inside a member function of Inner}; }}; â *end example*]
|
||||
498
cppdraft/expr/prop.md
Normal file
498
cppdraft/expr/prop.md
Normal file
@@ -0,0 +1,498 @@
|
||||
[expr.prop]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.2 Properties of expressions [expr.prop]
|
||||
|
||||
### [7.2.1](#basic.lval) Value category [[basic.lval]](basic.lval)
|
||||
|
||||
[1](#basic.lval-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L140)
|
||||
|
||||
Expressions are categorized according to the taxonomy in Figure [2](#fig:basic.lval)[.](#basic.lval-1.sentence-1)
|
||||
|
||||

|
||||
Figure [2](#fig:basic.lval) — Expression category taxonomy [[fig:basic.lval]](./fig:basic.lval)
|
||||
|
||||
- [(1.1)](#basic.lval-1.1)
|
||||
|
||||
A [*glvalue*](#def:glvalue "7.2.1 Value category [basic.lval]") is an expression whose evaluation determines the identity of an object, function, or non-static data member[.](#basic.lval-1.1.sentence-1)
|
||||
|
||||
- [(1.2)](#basic.lval-1.2)
|
||||
|
||||
A [*prvalue*](#def:prvalue "7.2.1 Value category [basic.lval]") is an expression whose evaluation initializes an object
|
||||
or computes the value of an operand of an operator,
|
||||
as specified by the context in which it appears,
|
||||
or an expression that has type cv void[.](#basic.lval-1.2.sentence-1)
|
||||
|
||||
- [(1.3)](#basic.lval-1.3)
|
||||
|
||||
An [*xvalue*](#def:xvalue "7.2.1 Value category [basic.lval]") is a glvalue that denotes an object whose resources can be reused (usually because it is near the end of its lifetime)[.](#basic.lval-1.3.sentence-1)
|
||||
|
||||
- [(1.4)](#basic.lval-1.4)
|
||||
|
||||
An [*lvalue*](#def:lvalue "7.2.1 Value category [basic.lval]") is a glvalue that is not an xvalue[.](#basic.lval-1.4.sentence-1)
|
||||
|
||||
- [(1.5)](#basic.lval-1.5)
|
||||
|
||||
An [*rvalue*](#def:rvalue "7.2.1 Value category [basic.lval]") is a prvalue or an xvalue[.](#basic.lval-1.5.sentence-1)
|
||||
|
||||
[2](#basic.lval-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L160)
|
||||
|
||||
Every expression belongs to exactly one of the fundamental categories in this
|
||||
taxonomy: lvalue, xvalue, or prvalue[.](#basic.lval-2.sentence-1)
|
||||
|
||||
This property of an expression is called
|
||||
its [*value category*](#def:value_category "7.2.1 Value category [basic.lval]")[.](#basic.lval-2.sentence-2)
|
||||
|
||||
[*Note [1](#basic.lval-note-1)*:
|
||||
|
||||
The discussion of each built-in operator in[[expr.compound]](expr.compound "7.6 Compound expressions") indicates the category of the value it yields and the value categories
|
||||
of the operands it expects[.](#basic.lval-2.sentence-3)
|
||||
|
||||
For example, the built-in assignment operators expect that
|
||||
the left operand is an lvalue and that the right operand is a prvalue and yield an
|
||||
lvalue as the result[.](#basic.lval-2.sentence-4)
|
||||
|
||||
User-defined operators are functions, and the categories of
|
||||
values they expect and yield are determined by their parameter and return types[.](#basic.lval-2.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#basic.lval-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L173)
|
||||
|
||||
[*Note [2](#basic.lval-note-2)*:
|
||||
|
||||
Historically, lvalues and rvalues were so-called
|
||||
because they could appear on the left- and right-hand side of an assignment
|
||||
(although this is no longer generally true);
|
||||
glvalues are âgeneralizedâ lvalues,
|
||||
prvalues are âpureâ rvalues,
|
||||
and xvalues are âeXpiringâ lvalues[.](#basic.lval-3.sentence-1)
|
||||
|
||||
Despite their names, these terms apply to expressions, not values[.](#basic.lval-3.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[4](#basic.lval-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L184)
|
||||
|
||||
[*Note [3](#basic.lval-note-3)*:
|
||||
|
||||
An expression is an xvalue if it is:
|
||||
|
||||
- [(4.1)](#basic.lval-4.1)
|
||||
|
||||
a move-eligible [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") ([[expr.prim.id.unqual]](expr.prim.id.unqual "7.5.5.2 Unqualified names"))
|
||||
or [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") ([[expr.prim.splice]](expr.prim.splice "7.5.9 Expression splicing")),
|
||||
|
||||
- [(4.2)](#basic.lval-4.2)
|
||||
|
||||
the result of calling a function, whether implicitly or explicitly,
|
||||
whose return type is an rvalue reference to object type ([[expr.call]](expr.call "7.6.1.3 Function call")),
|
||||
|
||||
- [(4.3)](#basic.lval-4.3)
|
||||
|
||||
a cast to an rvalue reference to
|
||||
object type ([[expr.type.conv]](expr.type.conv "7.6.1.4 Explicit type conversion (functional notation)"), [[expr.dynamic.cast]](expr.dynamic.cast "7.6.1.7 Dynamic cast"), [[expr.static.cast]](expr.static.cast "7.6.1.9 Static cast"), [[expr.reinterpret.cast]](expr.reinterpret.cast "7.6.1.10 Reinterpret cast"), [[expr.const.cast]](expr.const.cast "7.6.1.11 Const cast"), [[expr.cast]](expr.cast "7.6.3 Explicit type conversion (cast notation)")),
|
||||
|
||||
- [(4.4)](#basic.lval-4.4)
|
||||
|
||||
a subscripting operation with an xvalue array operand ([[expr.sub]](expr.sub "7.6.1.2 Subscripting")),
|
||||
|
||||
- [(4.5)](#basic.lval-4.5)
|
||||
|
||||
a class member access expression designating a non-static data member
|
||||
of non-reference type
|
||||
in which the object expression is an xvalue ([[expr.ref]](expr.ref "7.6.1.5 Class member access")), or
|
||||
|
||||
- [(4.6)](#basic.lval-4.6)
|
||||
|
||||
a .* pointer-to-member expression in which the first operand is
|
||||
an xvalue and the second operand is a pointer to data member ([[expr.mptr.oper]](expr.mptr.oper "7.6.4 Pointer-to-member operators"))[.](#basic.lval-4.sentence-1)
|
||||
|
||||
In general, the effect of this rule is that named rvalue references are
|
||||
treated as lvalues and unnamed rvalue references to objects are treated as
|
||||
xvalues; rvalue references to functions are treated as lvalues whether named or not[.](#basic.lval-4.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [1](#basic.lval-example-1)*: struct A {int m;};
|
||||
A&& operator+(A, A);
|
||||
A&& f();
|
||||
|
||||
A a;
|
||||
A&& ar = static_cast<A&&>(a);
|
||||
|
||||
The expressions f(), f().m, static_cast<A&&>(a), and a + a are xvalues[.](#basic.lval-4.sentence-3)
|
||||
|
||||
The expression ar is an lvalue[.](#basic.lval-4.sentence-4)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[5](#basic.lval-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L229)
|
||||
|
||||
The [*result*](#def:result,glvalue "7.2.1 Value category [basic.lval]") of a glvalue is the entity denoted by the expression[.](#basic.lval-5.sentence-1)
|
||||
|
||||
The [*result*](#def:result,prvalue "7.2.1 Value category [basic.lval]") of a prvalue
|
||||
is the value that the expression stores into its context;
|
||||
a prvalue that has type cv void has no result[.](#basic.lval-5.sentence-2)
|
||||
|
||||
A prvalue whose result is the value *V* is sometimes said to have or name the value *V*[.](#basic.lval-5.sentence-3)
|
||||
|
||||
The [*result object*](#def:result_object "7.2.1 Value category [basic.lval]") of a prvalue is the object initialized by the prvalue;
|
||||
a prvalue that has type cv void has no result object[.](#basic.lval-5.sentence-4)
|
||||
|
||||
[*Note [4](#basic.lval-note-4)*:
|
||||
|
||||
Except when the prvalue is the operand of a [*decltype-specifier*](dcl.type.decltype#nt:decltype-specifier "9.2.9.6 Decltype specifiers [dcl.type.decltype]"),
|
||||
a prvalue of object type always has a result object[.](#basic.lval-5.sentence-5)
|
||||
|
||||
For a discarded prvalue that has type other than cv void,
|
||||
a temporary object is materialized; see [[expr.context]](#expr.context "7.2.3 Context dependence")[.](#basic.lval-5.sentence-6)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[6](#basic.lval-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L246)
|
||||
|
||||
Whenever a glvalue appears as an operand of an operator that
|
||||
requires a prvalue for that operand, 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")),
|
||||
or function-to-pointer ([[conv.func]](conv.func "7.3.4 Function-to-pointer conversion")) standard conversions are
|
||||
applied to convert the expression to a prvalue[.](#basic.lval-6.sentence-1)
|
||||
|
||||
[*Note [5](#basic.lval-note-5)*:
|
||||
|
||||
An attempt to bind an rvalue reference to an lvalue is not such a context; see [[dcl.init.ref]](dcl.init.ref "9.5.4 References")[.](#basic.lval-6.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Note [6](#basic.lval-note-6)*:
|
||||
|
||||
Because cv-qualifiers are removed from the type of an expression of
|
||||
non-class type when the expression is converted to a prvalue, an lvalue
|
||||
of type const int can, for example, be used where
|
||||
a prvalue of type int is required[.](#basic.lval-6.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Note [7](#basic.lval-note-7)*:
|
||||
|
||||
There are no prvalue bit-fields; if a bit-field is converted to a
|
||||
prvalue ([[conv.lval]](conv.lval "7.3.2 Lvalue-to-rvalue conversion")), a prvalue of the type of the bit-field is
|
||||
created, which might then be promoted ([[conv.prom]](conv.prom "7.3.7 Integral promotions"))[.](#basic.lval-6.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[7](#basic.lval-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L267)
|
||||
|
||||
Unless otherwise specified ([[expr.reinterpret.cast]](expr.reinterpret.cast "7.6.1.10 Reinterpret cast"), [[expr.const.cast]](expr.const.cast "7.6.1.11 Const cast")),
|
||||
whenever a prvalue
|
||||
that is not the result of the lvalue-to-rvalue conversion ([[conv.lval]](conv.lval "7.3.2 Lvalue-to-rvalue conversion"))
|
||||
appears as an operand of an operator,
|
||||
the [temporary materialization conversion](conv.rval "7.3.5 Temporary materialization conversion [conv.rval]") is
|
||||
applied to convert the expression to an xvalue[.](#basic.lval-7.sentence-1)
|
||||
|
||||
[8](#basic.lval-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L275)
|
||||
|
||||
[*Note [8](#basic.lval-note-8)*:
|
||||
|
||||
The discussion of reference initialization in [[dcl.init.ref]](dcl.init.ref "9.5.4 References") and of
|
||||
temporaries in [[class.temporary]](class.temporary "6.8.7 Temporary objects") indicates the behavior of lvalues
|
||||
and rvalues in other significant contexts[.](#basic.lval-8.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[9](#basic.lval-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L282)
|
||||
|
||||
Unless otherwise indicated ([[dcl.type.decltype]](dcl.type.decltype "9.2.9.6 Decltype specifiers")),
|
||||
a prvalue shall always have complete type or the void type;
|
||||
if it has a class type or (possibly multidimensional) array of class type,
|
||||
that class shall not be an abstract class ([[class.abstract]](class.abstract "11.7.4 Abstract classes"))[.](#basic.lval-9.sentence-1)
|
||||
|
||||
A glvalue shall not have type cv void[.](#basic.lval-9.sentence-2)
|
||||
|
||||
[*Note [9](#basic.lval-note-9)*:
|
||||
|
||||
A glvalue can have complete or incomplete non-void type[.](#basic.lval-9.sentence-3)
|
||||
|
||||
Class and array prvalues can have cv-qualified types; other prvalues
|
||||
always have cv-unqualified types[.](#basic.lval-9.sentence-4)
|
||||
|
||||
See [[expr.type]](#expr.type "7.2.2 Type")[.](#basic.lval-9.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[10](#basic.lval-10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L294)
|
||||
|
||||
An lvalue is [*modifiable*](#def:modifiable "7.2.1 Value category [basic.lval]") unless its type is const-qualified
|
||||
or is a function type[.](#basic.lval-10.sentence-1)
|
||||
|
||||
[*Note [10](#basic.lval-note-10)*:
|
||||
|
||||
A program that attempts
|
||||
to modify an object through a nonmodifiable lvalue or through an rvalue
|
||||
is ill-formed ([[expr.assign]](expr.assign "7.6.19 Assignment and compound assignment operators"), [[expr.post.incr]](expr.post.incr "7.6.1.6 Increment and decrement"), [[expr.pre.incr]](expr.pre.incr "7.6.2.3 Increment and decrement"))[.](#basic.lval-10.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[11](#basic.lval-11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L303)
|
||||
|
||||
An object of dynamic type Tobj is[*type-accessible*](#def:type-accessible "7.2.1 Value category [basic.lval]") through a glvalue of type Tref if Tref is similar ([[conv.qual]](conv.qual "7.3.6 Qualification conversions")) to:
|
||||
|
||||
- [(11.1)](#basic.lval-11.1)
|
||||
|
||||
Tobj,
|
||||
|
||||
- [(11.2)](#basic.lval-11.2)
|
||||
|
||||
a type that is the signed or unsigned type corresponding to Tobj, or
|
||||
|
||||
- [(11.3)](#basic.lval-11.3)
|
||||
|
||||
a char, unsigned char, or std::byte type[.](#basic.lval-11.sentence-1)
|
||||
|
||||
If a program attempts to access ([[defns.access]](defns.access "3.1 access"))
|
||||
the stored value of an object through a glvalue
|
||||
through which it is not type-accessible,
|
||||
the behavior is undefined[.](#basic.lval-11.sentence-2)[42](#footnote-42 "The intent of this list is to specify those circumstances in which an object can or cannot be aliased.")
|
||||
|
||||
If a program invokes
|
||||
a defaulted copy/move constructor or copy/move assignment operator
|
||||
for a union of type U with a glvalue argument
|
||||
that does not denote an object of type cv U within its lifetime,
|
||||
the behavior is undefined[.](#basic.lval-11.sentence-3)
|
||||
|
||||
[*Note [11](#basic.lval-note-11)*:
|
||||
|
||||
In C, an entire object of structure type can be accessed, e.g., using assignment[.](#basic.lval-11.sentence-4)
|
||||
|
||||
By contrast, C++ has no notion of accessing an object of class type
|
||||
through an lvalue of class type[.](#basic.lval-11.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[42)](#footnote-42)[42)](#footnoteref-42)
|
||||
|
||||
The intent of this list is to specify those circumstances in which an
|
||||
object can or cannot be aliased[.](#footnote-42.sentence-1)
|
||||
|
||||
### [7.2.2](#expr.type) Type [[expr.type]](expr.type)
|
||||
|
||||
[1](#expr.type-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L335)
|
||||
|
||||
If an expression initially has the type âreference toTâ ([[dcl.ref]](dcl.ref "9.3.4.3 References"), [[dcl.init.ref]](dcl.init.ref "9.5.4 References")), the type is adjusted toT prior to any further analysis;
|
||||
the value category of the expression is not altered[.](#expr.type-1.sentence-1)
|
||||
|
||||
Let X be the object or function denoted by the reference[.](#expr.type-1.sentence-2)
|
||||
|
||||
If a pointer to X would be valid in
|
||||
the context of the evaluation of the expression ([[basic.fundamental]](basic.fundamental "6.9.2 Fundamental types")),
|
||||
the result designates X;
|
||||
otherwise, the behavior is undefined[.](#expr.type-1.sentence-3)
|
||||
|
||||
[*Note [1](#expr.type-note-1)*:
|
||||
|
||||
Before the lifetime of the reference has started or after it has ended,
|
||||
the behavior is undefined (see [[basic.life]](basic.life "6.8.4 Lifetime"))[.](#expr.type-1.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#expr.type-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L351)
|
||||
|
||||
If a prvalue initially has the type âcv Tâ, whereT is a cv-unqualified non-class, non-array type, the type of
|
||||
the expression is adjusted to T prior to any further analysis[.](#expr.type-2.sentence-1)
|
||||
|
||||
[3](#expr.type-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L356)
|
||||
|
||||
The [*composite pointer type*](#def:composite_pointer_type "7.2.2 Type [expr.type]") of
|
||||
two operands p1 andp2 having types T1 and T2, respectively, where at least one is a
|
||||
pointer or pointer-to-member type orstd::nullptr_t, is:
|
||||
|
||||
- [(3.1)](#expr.type-3.1)
|
||||
|
||||
if both p1 and p2 are null pointer constants,std::nullptr_t;
|
||||
|
||||
- [(3.2)](#expr.type-3.2)
|
||||
|
||||
if either p1 or p2 is a null pointer constant, T2 or T1,
|
||||
respectively;
|
||||
|
||||
- [(3.3)](#expr.type-3.3)
|
||||
|
||||
if T1 or T2 is âpointer to *cv1* voidâ and the
|
||||
other type is âpointer to *cv2* Tâ,
|
||||
where T is an object type or void,
|
||||
âpointer to *cv12* voidâ,
|
||||
where *cv12* is the union of *cv1* and *cv2*;
|
||||
|
||||
- [(3.4)](#expr.type-3.4)
|
||||
|
||||
if T1 or T2 is âpointer to noexcept functionâ and the
|
||||
other type is âpointer to functionâ, where the function types are otherwise the same,
|
||||
âpointer to functionâ;
|
||||
|
||||
- [(3.5)](#expr.type-3.5)
|
||||
|
||||
if T1 is âpointer to C1â and T2 is âpointer toC2â, where C1 is reference-related to C2 or C2 is
|
||||
reference-related to C1 ([[dcl.init.ref]](dcl.init.ref "9.5.4 References")),
|
||||
the qualification-combined type ([[conv.qual]](conv.qual "7.3.6 Qualification conversions"))
|
||||
of T1 and T2 or the qualification-combined type of T2 and T1,
|
||||
respectively;
|
||||
|
||||
- [(3.6)](#expr.type-3.6)
|
||||
|
||||
if T1 or T2 is
|
||||
âpointer to member of C1 of type functionâ,
|
||||
the other type is
|
||||
âpointer to member of C2 of type noexcept functionâ, andC1 is reference-related to C2 orC2 is reference-related to C1 ([[dcl.init.ref]](dcl.init.ref "9.5.4 References")),
|
||||
where the function types are otherwise the same,
|
||||
âpointer to member of C2 of type functionâ or
|
||||
âpointer to member of C1 of type functionâ, respectively;
|
||||
|
||||
- [(3.7)](#expr.type-3.7)
|
||||
|
||||
if T1 is
|
||||
âpointer to member of C1 of type *cv1* Uâ andT2 is
|
||||
âpointer to member of C2 of type *cv2* Uâ,
|
||||
for some non-function type U,
|
||||
where C1 is
|
||||
reference-related to C2 or C2 is reference-related toC1 ([[dcl.init.ref]](dcl.init.ref "9.5.4 References")), the qualification-combined type of T2 and T1 or the qualification-combined type
|
||||
of T1 and T2, respectively;
|
||||
|
||||
- [(3.8)](#expr.type-3.8)
|
||||
|
||||
if T1 and T2 are similar types ([[conv.qual]](conv.qual "7.3.6 Qualification conversions")), the qualification-combined type of T1 andT2;
|
||||
|
||||
- [(3.9)](#expr.type-3.9)
|
||||
|
||||
otherwise, a program that necessitates the determination of a
|
||||
composite pointer type is ill-formed[.](#expr.type-3.sentence-1)
|
||||
|
||||
[*Example [1](#expr.type-example-1)*: typedef void *p;typedef const int *q;typedef int **pi;typedef const int **pci;
|
||||
|
||||
The composite pointer type of p and q is âpointer to const voidâ; the
|
||||
composite pointer type of pi and pci is âpointer to const pointer toconst intâ[.](#expr.type-3.sentence-2)
|
||||
|
||||
â *end example*]
|
||||
|
||||
### [7.2.3](#expr.context) Context dependence [[expr.context]](expr.context)
|
||||
|
||||
[1](#expr.context-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L438)
|
||||
|
||||
In some contexts, [*unevaluated operands*](#def:unevaluated_operand "7.2.3 Context dependence [expr.context]") appear ([[expr.prim.req.simple]](expr.prim.req.simple "7.5.8.2 Simple requirements"), [[expr.prim.req.compound]](expr.prim.req.compound "7.5.8.4 Compound requirements"), [[expr.typeid]](expr.typeid "7.6.1.8 Type identification"), [[expr.sizeof]](expr.sizeof "7.6.2.5 Sizeof"), [[expr.unary.noexcept]](expr.unary.noexcept "7.6.2.7 noexcept operator"), [[expr.reflect]](expr.reflect "7.6.2.10 The reflection operator"), [[dcl.type.decltype]](dcl.type.decltype "9.2.9.6 Decltype specifiers"), [[temp.pre]](temp.pre "13.1 Preamble"), [[temp.concept]](temp.concept "13.7.9 Concept definitions"))[.](#expr.context-1.sentence-1)
|
||||
|
||||
An unevaluated operand is not evaluated[.](#expr.context-1.sentence-2)
|
||||
|
||||
[*Note [1](#expr.context-note-1)*:
|
||||
|
||||
In an unevaluated operand, a non-static class member can be
|
||||
named ([[expr.prim.id]](expr.prim.id "7.5.5 Names")) and naming of objects or functions does not, by
|
||||
itself, require that a definition be provided ([[basic.def.odr]](basic.def.odr "6.3 One-definition rule"))[.](#expr.context-1.sentence-3)
|
||||
|
||||
An unevaluated operand is considered a [full-expression](intro.execution#def:full-expression "6.10.1 Sequential execution [intro.execution]")[.](#expr.context-1.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#expr.context-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L458)
|
||||
|
||||
In some contexts, an expression only appears for its side effects[.](#expr.context-2.sentence-1)
|
||||
|
||||
Such an
|
||||
expression is called a [*discarded-value expression*](#def:discarded-value_expression "7.2.3 Context dependence [expr.context]")[.](#expr.context-2.sentence-2)
|
||||
|
||||
The [array-to-pointer](conv.array "7.3.3 Array-to-pointer conversion [conv.array]") and [function-to-pointer](conv.func "7.3.4 Function-to-pointer conversion [conv.func]") standard conversions are not
|
||||
applied[.](#expr.context-2.sentence-3)
|
||||
|
||||
The [lvalue-to-rvalue](conv.lval "7.3.2 Lvalue-to-rvalue conversion [conv.lval]") conversion is applied
|
||||
if and only if
|
||||
the expression is a glvalue of volatile-qualified type and it is one of the
|
||||
following:
|
||||
|
||||
- [(2.1)](#expr.context-2.1)
|
||||
|
||||
( [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") ), where[*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") is one of these expressions,
|
||||
|
||||
- [(2.2)](#expr.context-2.2)
|
||||
|
||||
[*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") ([[expr.prim.id]](expr.prim.id "7.5.5 Names")),
|
||||
|
||||
- [(2.3)](#expr.context-2.3)
|
||||
|
||||
[*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") ([[expr.prim.splice]](expr.prim.splice "7.5.9 Expression splicing")),
|
||||
|
||||
- [(2.4)](#expr.context-2.4)
|
||||
|
||||
[subscripting](expr.sub "7.6.1.2 Subscripting [expr.sub]"),
|
||||
|
||||
- [(2.5)](#expr.context-2.5)
|
||||
|
||||
[class member access](expr.ref "7.6.1.5 Class member access [expr.ref]"),
|
||||
|
||||
- [(2.6)](#expr.context-2.6)
|
||||
|
||||
[indirection](expr.unary.op#def:indirection "7.6.2.2 Unary operators [expr.unary.op]"),
|
||||
|
||||
- [(2.7)](#expr.context-2.7)
|
||||
|
||||
[pointer-to-member operation](expr.mptr.oper "7.6.4 Pointer-to-member operators [expr.mptr.oper]"),
|
||||
|
||||
- [(2.8)](#expr.context-2.8)
|
||||
|
||||
[conditional expression](expr.cond "7.6.16 Conditional operator [expr.cond]") where both the second and the
|
||||
third operands are one of these expressions, or
|
||||
|
||||
- [(2.9)](#expr.context-2.9)
|
||||
|
||||
[comma expression](expr.comma "7.6.20 Comma operator [expr.comma]") where the right operand is one of
|
||||
these expressions[.](#expr.context-2.sentence-4)
|
||||
|
||||
[*Note [2](#expr.context-note-2)*:
|
||||
|
||||
Using an overloaded operator causes a function call; the
|
||||
above covers only operators with built-in meaning[.](#expr.context-2.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
The temporary materialization conversion ([[conv.rval]](conv.rval "7.3.5 Temporary materialization conversion")) is applied
|
||||
if the (possibly converted) expression is a prvalue of object type[.](#expr.context-2.sentence-6)
|
||||
|
||||
[*Note [3](#expr.context-note-3)*:
|
||||
|
||||
If the original expression is an lvalue of class type,
|
||||
it must have a volatile copy constructor to initialize the temporary object
|
||||
that is the result object of the temporary materialization conversion[.](#expr.context-2.sentence-7)
|
||||
|
||||
â *end note*]
|
||||
|
||||
The expression is evaluated and its result (if any) is discarded[.](#expr.context-2.sentence-8)
|
||||
243
cppdraft/expr/ref.md
Normal file
243
cppdraft/expr/ref.md
Normal file
@@ -0,0 +1,243 @@
|
||||
[expr.ref]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.ref)
|
||||
|
||||
### 7.6.1 Postfix expressions [[expr.post]](expr.post#expr.ref)
|
||||
|
||||
#### 7.6.1.5 Class member access [expr.ref]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4128)
|
||||
|
||||
A postfix expression followed by a dot . or an arrow ->,
|
||||
optionally followed by the keywordtemplate, and then followed by an[*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") or a [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]"),
|
||||
is a postfix expression[.](#1.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
If the keyword template is used and
|
||||
followed by an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]"),
|
||||
the unqualified name
|
||||
is considered to refer to a template ([[temp.names]](temp.names "13.3 Names of template specializations"))[.](#1.sentence-2)
|
||||
|
||||
If a [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]") results and is followed by a ::,
|
||||
the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") is a [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]")[.](#1.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4153)
|
||||
|
||||
For a dot that is followed by an expression
|
||||
that designates a static member or an enumerator,
|
||||
the first expression is a discarded-value expression ([[expr.context]](expr.context "7.2.3 Context dependence"));
|
||||
if the expression after the dot designates a non-static data member,
|
||||
the first expression shall be a glvalue[.](#2.sentence-1)
|
||||
|
||||
A postfix expression that is followed by an arrow
|
||||
shall be a prvalue having pointer type[.](#2.sentence-2)
|
||||
|
||||
The expression E1->E2 is
|
||||
converted to the equivalent form (*(E1)).E2; the remainder of
|
||||
[expr.ref] will address only the form using a dot[.](#2.sentence-3)[49](#footnote-49 "Note that (*(E1)) is an lvalue.")
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4170)
|
||||
|
||||
The postfix expression before the dot is evaluated;[50](#footnote-50 "If the class member access expression is evaluated, the subexpression evaluation happens even if the result is unnecessary to determine the value of the entire postfix expression, for example if the id-expression denotes a static member.") the result of that evaluation,
|
||||
together with
|
||||
the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") or [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]"),
|
||||
determines the result of the entire postfix expression[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4184)
|
||||
|
||||
Abbreviating[*postfix-expression*](expr.post.general#nt:postfix-expression "7.6.1.1 General [expr.post.general]").[*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") or[*postfix-expression*](expr.post.general#nt:postfix-expression "7.6.1.1 General [expr.post.general]").[*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]") as E1.E2, E1 is called the [*object expression*](expr.mptr.oper#def:object_expression "7.6.4 Pointer-to-member operators [expr.mptr.oper]")[.](#4.sentence-1)
|
||||
|
||||
If the object expression is of scalar type,E2 shall name the pseudo-destructor
|
||||
of that same type (ignoring cv-qualifications) andE1.E2 is a prvalue of type âfunction of () returning voidâ[.](#4.sentence-2)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
This value can only be used
|
||||
for a notional function call ([[expr.prim.id.dtor]](expr.prim.id.dtor "7.5.5.5 Destruction"))[.](#4.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4198)
|
||||
|
||||
Otherwise, the object expression shall be of class type[.](#5.sentence-1)
|
||||
|
||||
The class type shall be complete
|
||||
unless the class member access appears in the definition of that class[.](#5.sentence-2)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
The program is ill-formed if the result differs from that
|
||||
when the class is complete ([[class.member.lookup]](class.member.lookup "6.5.2 Member name lookup"))[.](#5.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Note [4](#note-4)*:
|
||||
|
||||
[[basic.lookup.qual]](basic.lookup.qual "6.5.5 Qualified name lookup") describes how names are looked up after the. and -> operators[.](#5.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4211)
|
||||
|
||||
If E2 is a [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]"),
|
||||
then let T1 be the type of E1[.](#6.sentence-1)
|
||||
|
||||
E2 shall designate either
|
||||
a member of T1 or
|
||||
a direct base class relationship (T1, B)[.](#6.sentence-2)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4218)
|
||||
|
||||
If E2 designates a bit-field, E1.E2 is a bit-field[.](#7.sentence-1)
|
||||
|
||||
The
|
||||
type and value category of E1.E2 are determined as follows[.](#7.sentence-2)
|
||||
|
||||
In the remainder of [expr.ref], *cq* represents eitherconst or the absence of const and *vq* represents
|
||||
either volatile or the absence of volatile[.](#7.sentence-3)
|
||||
|
||||
*cv* represents an arbitrary set of cv-qualifiers, as defined
|
||||
in [[basic.type.qualifier]](basic.type.qualifier "6.9.5 CV-qualifiers")[.](#7.sentence-4)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4227)
|
||||
|
||||
If E2 designates an entity
|
||||
that is declared to have type âreference to Tâ, thenE1.E2 is an lvalue of type T[.](#8.sentence-1)
|
||||
|
||||
In that case, if E2 designates a static data member,E1.E2 designates the object or function to which
|
||||
the reference is bound,
|
||||
otherwise E1.E2 designates the object or function to which
|
||||
the corresponding reference member of E1 is bound[.](#8.sentence-2)
|
||||
|
||||
Otherwise, one of the following rules applies[.](#8.sentence-3)
|
||||
|
||||
- [(8.1)](#8.1)
|
||||
|
||||
If E2 designates a static data member and the type of E2 is T, then E1.E2 is an lvalue; the expression designates
|
||||
the named member of the class[.](#8.1.sentence-1)
|
||||
The type of E1.E2 is T[.](#8.1.sentence-2)
|
||||
|
||||
- [(8.2)](#8.2)
|
||||
|
||||
Otherwise, if E2 designates a non-static data member and the type ofE1 is â*cq1 vq1* Xâ, and the type of E2 is â*cq2 vq2* Tâ, the expression designates the corresponding
|
||||
member subobject of the object designated by E1[.](#8.2.sentence-1)
|
||||
If E1 is an lvalue, then E1.E2 is an lvalue;
|
||||
otherwise E1.E2 is an xvalue[.](#8.2.sentence-2)
|
||||
Let the notation *vq12* stand for the âunionâ of*vq1* and *vq2*; that is, if *vq1* or *vq2* is volatile, then *vq12* is volatile[.](#8.2.sentence-3)
|
||||
Similarly,
|
||||
let the notation *cq12* stand for the âunionâ of *cq1* and *cq2*; that is, if *cq1* or *cq2* isconst, then *cq12* is const[.](#8.2.sentence-4)
|
||||
If the entity designated by E2 is declared to be a mutable member,
|
||||
then the type of E1.E2 is â*vq12* Tâ[.](#8.2.sentence-5)
|
||||
If the entity designated by E2 is not declared to be a mutable member,
|
||||
then the type of E1.E2 is â*cq12* *vq12* Tâ[.](#8.2.sentence-6)
|
||||
|
||||
- [(8.3)](#8.3)
|
||||
|
||||
Otherwise, if E2 denotes an overload set,
|
||||
the expression shall be the (possibly-parenthesized) left-hand operand of
|
||||
a member function call ([[expr.call]](expr.call "7.6.1.3 Function call")), and
|
||||
function overload resolution ([[over.match]](over.match "12.2 Overload resolution"))
|
||||
is used to select the function to which E2 refers[.](#8.3.sentence-1)
|
||||
The type of E1.E2 is the type of E2 and E1.E2 refers to the function referred to by E2[.](#8.3.sentence-2)
|
||||
|
||||
* [(8.3.1)](#8.3.1)
|
||||
|
||||
If E2 refers to a static member function,E1.E2 is an lvalue[.](#8.3.1.sentence-1)
|
||||
|
||||
* [(8.3.2)](#8.3.2)
|
||||
|
||||
Otherwise (when E2 refers to a non-static member function),E1.E2 is a prvalue[.](#8.3.2.sentence-1)
|
||||
[*Note [5](#note-5)*:
|
||||
Any redundant set of parentheses surrounding the expression
|
||||
is ignored ([[expr.prim.paren]](expr.prim.paren "7.5.4 Parentheses"))[.](#8.3.2.sentence-2)
|
||||
â *end note*]
|
||||
|
||||
- [(8.4)](#8.4)
|
||||
|
||||
Otherwise, if E2 designates a nested type,
|
||||
the expression E1.E2 is ill-formed[.](#8.4.sentence-1)
|
||||
|
||||
- [(8.5)](#8.5)
|
||||
|
||||
Otherwise, if E2 designates a member enumerator and the type of E2 is T, the expression E1.E2 is a prvalue of type T whose value is the value of the enumerator[.](#8.5.sentence-1)
|
||||
|
||||
- [(8.6)](#8.6)
|
||||
|
||||
Otherwise, if E2 designates a direct base class relationship (D,B) and the type of E1 is cv T,
|
||||
the expression designates the direct base class subobject of type B of the object designated by E1[.](#8.6.sentence-1)
|
||||
If E1 is an lvalue,
|
||||
then E1.E2 is an lvalue;
|
||||
otherwise, E1.E2 is an xvalue[.](#8.6.sentence-2)
|
||||
The type of E1.E2 is âcv Bâ[.](#8.6.sentence-3)
|
||||
[*Note [6](#note-6)*:
|
||||
This can only occur in an expression of the form e1.[:e2:][.](#8.6.sentence-4)
|
||||
â *end note*]
|
||||
[*Example [1](#example-1)*: struct B {int b;};struct C : B {int get() const { return b; }};struct D : B, C { };
|
||||
|
||||
constexpr int f() { D d = {1, {}}; // b unambiguously refers to the direct base class of type B,// not the indirect base class of type B B& b = d.[: std::meta::bases_of(^^D, std::meta::access_context::current())[0] :];
|
||||
b.b += 10; return 10 * b.b + d.get();}static_assert(f() == 110); â *end example*]
|
||||
|
||||
- [(8.7)](#8.7)
|
||||
|
||||
Otherwise, the program is ill-formed[.](#8.7.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4332)
|
||||
|
||||
If E2 designates a non-static member
|
||||
(possibly after overload resolution),
|
||||
the program is ill-formed if the class of which E2 designates
|
||||
a direct member is an ambiguous base ([[class.member.lookup]](class.member.lookup "6.5.2 Member name lookup")) of
|
||||
the designating class ([[class.access.base]](class.access.base "11.8.3 Accessibility of base classes and base class members")) of E2[.](#9.sentence-1)
|
||||
|
||||
[*Note [7](#note-7)*:
|
||||
|
||||
The program is also ill-formed if the naming class is an ambiguous base of the class type
|
||||
of the object expression; see [[class.access.base]](class.access.base "11.8.3 Accessibility of base classes and base class members")[.](#9.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4343)
|
||||
|
||||
If E2 designates a non-static member
|
||||
(possibly after overload resolution) and
|
||||
the result of E1 is an object whose type
|
||||
is not similar ([[conv.qual]](conv.qual "7.3.6 Qualification conversions")) to the type of E1,
|
||||
the behavior is undefined[.](#10.sentence-1)
|
||||
|
||||
[*Example [2](#example-2)*: struct A { int i; };struct B { int j; };struct D : A, B {};void f() { D d; static_cast<B&>(d).j; // OK, object expression designates the B subobject of dreinterpret_cast<B&>(d).j; // undefined behavior} â *end example*]
|
||||
|
||||
[49)](#footnote-49)[49)](#footnoteref-49)
|
||||
|
||||
Note that(*(E1)) is an lvalue[.](#footnote-49.sentence-1)
|
||||
|
||||
[50)](#footnote-50)[50)](#footnoteref-50)
|
||||
|
||||
If the class member
|
||||
access expression is evaluated, the subexpression evaluation happens even if the
|
||||
result is unnecessary to determine
|
||||
the value of the entire postfix expression, for example if the[*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") denotes a static member[.](#footnote-50.sentence-1)
|
||||
219
cppdraft/expr/reflect.md
Normal file
219
cppdraft/expr/reflect.md
Normal file
@@ -0,0 +1,219 @@
|
||||
[expr.reflect]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.reflect)
|
||||
|
||||
### 7.6.2 Unary expressions [[expr.unary]](expr.unary#expr.reflect)
|
||||
|
||||
#### 7.6.2.10 The reflection operator [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](#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"))[.](#1.sentence-1)
|
||||
|
||||
[*Note [1](#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*[.](#1.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#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]")[.](#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[.](#2.sentence-2)
|
||||
|
||||
[3](#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]")[.](#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 <[.](#3.sentence-2)
|
||||
|
||||
[*Example [1](#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](#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[.](#4.sentence-1)
|
||||
|
||||
[5](#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)](#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[.](#5.1.sentence-1)
|
||||
[*Example [2](#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)](#5.2)
|
||||
|
||||
Otherwise, if lookup finds a namespace alias ([[namespace.alias]](namespace.alias "9.9.3 Namespace alias")),R represents that namespace alias[.](#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[.](#5.2.sentence-2)
|
||||
|
||||
- [(5.3)](#5.3)
|
||||
|
||||
Otherwise, if lookup finds a namespace ([[basic.namespace]](basic.namespace "9.9 Namespaces")),R represents that namespace[.](#5.3.sentence-1)
|
||||
|
||||
- [(5.4)](#5.4)
|
||||
|
||||
Otherwise, if lookup finds a concept ([[temp.concept]](temp.concept "13.7.9 Concept definitions")),R represents the denoted concept[.](#5.4.sentence-1)
|
||||
|
||||
- [(5.5)](#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)](#5.5.1)
|
||||
|
||||
If lookup finds an injected-class-name ([[class.pre]](class.pre "11.1 Preamble")), then:
|
||||
+
|
||||
[(5.5.1.1)](#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[.](#5.5.1.1.sentence-1)
|
||||
|
||||
+
|
||||
[(5.5.1.2)](#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[.](#5.5.1.2.sentence-1)
|
||||
|
||||
* [(5.5.2)](#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[.](#5.5.2.sentence-1)
|
||||
|
||||
* [(5.5.3)](#5.5.3)
|
||||
|
||||
Otherwise, if lookup finds
|
||||
a class template, variable template, or alias template,R represents that template[.](#5.5.3.sentence-1)
|
||||
[*Note [2](#note-2)*:
|
||||
Lookup never finds a partial or explicit specialization[.](#5.5.3.sentence-2)
|
||||
â *end note*]
|
||||
|
||||
- [(5.6)](#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[.](#5.6.sentence-1)
|
||||
|
||||
- [(5.7)](#5.7)
|
||||
|
||||
Otherwise, if lookup finds a class or an enumeration,R represents the denoted type[.](#5.7.sentence-1)
|
||||
|
||||
- [(5.8)](#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[.](#5.8.sentence-1)
|
||||
|
||||
- [(5.9)](#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)[.](#5.9.sentence-1)
|
||||
|
||||
[6](#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)](#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[.](#6.1.sentence-1)
|
||||
|
||||
- [(6.2)](#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[.](#6.2.sentence-1)
|
||||
|
||||
- [(6.3)](#6.3)
|
||||
|
||||
Otherwise, R represents the type denoted by the [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]")[.](#6.3.sentence-1)
|
||||
|
||||
[7](#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)](#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)](#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)](#7.1.2)
|
||||
|
||||
a function-local predefined variable ([[dcl.fct.def.general]](dcl.fct.def.general "9.6.1 General")),
|
||||
|
||||
* [(7.1.3)](#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)](#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[.](#7.1.sentence-1)
|
||||
|
||||
- [(7.2)](#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[.](#7.2.sentence-1)
|
||||
|
||||
- [(7.3)](#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[.](#7.3.sentence-1)
|
||||
|
||||
- [(7.4)](#7.4)
|
||||
|
||||
Otherwise, R is ill-formed[.](#7.4.sentence-1)
|
||||
[*Note [3](#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*[.](#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"))[.](#7.sentence-2)
|
||||
|
||||
[*Example [3](#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*]
|
||||
221
cppdraft/expr/reinterpret/cast.md
Normal file
221
cppdraft/expr/reinterpret/cast.md
Normal file
@@ -0,0 +1,221 @@
|
||||
[expr.reinterpret.cast]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.reinterpret.cast)
|
||||
|
||||
### 7.6.1 Postfix expressions [[expr.post]](expr.post#expr.reinterpret.cast)
|
||||
|
||||
#### 7.6.1.10 Reinterpret cast [expr.reinterpret.cast]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4880)
|
||||
|
||||
The result of the expression reinterpret_cast<T>(v) is the
|
||||
result of converting the expression v to type T[.](#1.sentence-1)
|
||||
|
||||
If T is an lvalue reference type or an rvalue reference to function type, the result is an lvalue;
|
||||
if T is an rvalue reference to object type, the result is an xvalue;
|
||||
otherwise, the result is a prvalue and the[lvalue-to-rvalue](conv.lval "7.3.2 Lvalue-to-rvalue conversion [conv.lval]"), [array-to-pointer](conv.array "7.3.3 Array-to-pointer conversion [conv.array]"),
|
||||
and [function-to-pointer](conv.func "7.3.4 Function-to-pointer conversion [conv.func]") standard conversions are
|
||||
performed on the expression v[.](#1.sentence-2)
|
||||
|
||||
Conversions that can be performed explicitly
|
||||
using reinterpret_cast are listed below[.](#1.sentence-3)
|
||||
|
||||
No other conversion can
|
||||
be performed explicitly using reinterpret_cast[.](#1.sentence-4)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4896)
|
||||
|
||||
The reinterpret_cast operator shall not cast away constness ([[expr.const.cast]](expr.const.cast "7.6.1.11 Const cast"))[.](#2.sentence-1)
|
||||
|
||||
An expression of integral, enumeration, pointer, or pointer-to-member type
|
||||
can be explicitly converted to its own type; such a cast yields the value of
|
||||
its operand[.](#2.sentence-2)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4902)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
The mapping performed by reinterpret_cast might, or might not, produce a
|
||||
representation different from the original value[.](#3.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4908)
|
||||
|
||||
A pointer can be explicitly converted to any integral type large enough
|
||||
to hold all values of its type[.](#4.sentence-1)
|
||||
|
||||
The mapping function is implementation-defined[.](#4.sentence-2)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
It is intended to be unsurprising to those who know the addressing
|
||||
structure of the underlying machine[.](#4.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
A value of type std::nullptr_t can be converted to an integral
|
||||
type; the conversion has the same meaning and validity as a conversion of(void*)0 to the integral type[.](#4.sentence-4)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
A reinterpret_cast cannot be used to convert a value of any type to the typestd::nullptr_t[.](#4.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4928)
|
||||
|
||||
A value of integral type or enumeration type can be explicitly converted
|
||||
to a pointer[.](#5.sentence-1)
|
||||
|
||||
A pointer converted to an integer of sufficient size (if
|
||||
any such exists on the implementation) and back to the same pointer type
|
||||
will have its original value ([[basic.compound]](basic.compound "6.9.4 Compound types"));mappings between pointers and integers are otherwiseimplementation-defined[.](#5.sentence-2)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4939)
|
||||
|
||||
A function pointer can be explicitly converted
|
||||
to a function pointer of a different type[.](#6.sentence-1)
|
||||
|
||||
[*Note [4](#note-4)*:
|
||||
|
||||
The effect of calling a function through a pointer to a function
|
||||
type ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")) that is not the same as the type used in the
|
||||
definition of the function is undefined ([[expr.call]](expr.call "7.6.1.3 Function call"))[.](#6.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
Except that converting
|
||||
a prvalue of type âpointer to T1â to the type âpointer toT2â (where T1 and T2 are function types) and
|
||||
back to its original type yields the original pointer value, the result
|
||||
of such a pointer conversion is unspecified[.](#6.sentence-3)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4957)
|
||||
|
||||
An object pointer
|
||||
can be explicitly converted to an object pointer of a different type[.](#7.sentence-1)[53](#footnote-53 "The types can have different cv-qualifiers, subject to the overall restriction that a reinterpret_cast cannot cast away constness.")
|
||||
|
||||
When a prvalue v of object pointer type is converted to
|
||||
the object pointer type âpointer to cv Tâ, the result is static_cast<cv T*>(static_cast<cv void*>(v))[.](#7.sentence-2)
|
||||
|
||||
[*Note [5](#note-5)*:
|
||||
|
||||
Converting a pointer of type âpointer to T1â
|
||||
that points to an object of type T1 to the type âpointer to T2â
|
||||
(where T2 is an object type
|
||||
and the alignment requirements of T2 are no stricter than those of T1)
|
||||
and back to its original type yields the original pointer value[.](#7.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4978)
|
||||
|
||||
Converting a function pointer to an object pointer
|
||||
type or vice versa is
|
||||
conditionally-supported[.](#8.sentence-1)
|
||||
|
||||
The meaning of such a conversion isimplementation-defined,
|
||||
except that if an implementation
|
||||
supports conversions in both directions, converting a prvalue of one type to the other
|
||||
type and back, possibly with different cv-qualification, shall yield the original
|
||||
pointer value[.](#8.sentence-2)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4988)
|
||||
|
||||
The null pointer value ([[basic.compound]](basic.compound "6.9.4 Compound types")) is converted to the null pointer value
|
||||
of the destination type[.](#9.sentence-1)
|
||||
|
||||
[*Note [6](#note-6)*:
|
||||
|
||||
A null pointer constant of type std::nullptr_t cannot be converted to a
|
||||
pointer type, and a null pointer constant of integral type is not necessarily
|
||||
converted to a null pointer value[.](#9.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4997)
|
||||
|
||||
A prvalue of type âpointer to member of X of type T1â
|
||||
can be explicitly converted to a prvalue of a different type âpointer to member ofY of type T2â if T1 and T2 are both
|
||||
function types or both object types[.](#10.sentence-1)[54](#footnote-54 "T1 and T2 can have different cv-qualifiers, subject to the overall restriction that a reinterpret_cast cannot cast away constness.")
|
||||
|
||||
The null member pointer value ([[conv.mem]](conv.mem "7.3.13 Pointer-to-member conversions")) is converted to the
|
||||
null member pointer value of the destination type[.](#10.sentence-2)
|
||||
|
||||
The result of this
|
||||
conversion is unspecified, except in the following cases:
|
||||
|
||||
- [(10.1)](#10.1)
|
||||
|
||||
Converting a prvalue of type âpointer to member functionâ to a
|
||||
different pointer-to-member-function type and back to its original type
|
||||
yields the original pointer-to-member value[.](#10.1.sentence-1)
|
||||
|
||||
- [(10.2)](#10.2)
|
||||
|
||||
Converting a prvalue of type âpointer to data member of X of type T1â to the type âpointer to data member of Y of type T2â (where the alignment requirements of T2 are
|
||||
no stricter than those of T1) and back to its original type
|
||||
yields the original pointer-to-member value[.](#10.2.sentence-1)
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5025)
|
||||
|
||||
If v is a glvalue of type T1,
|
||||
designating an object or function *x*,
|
||||
it can be cast to the type âreference to T2â
|
||||
if an expression of type âpointer to T1â
|
||||
can be explicitly converted to the type âpointer to T2â
|
||||
using a reinterpret_cast[.](#11.sentence-1)
|
||||
|
||||
The result is that of *reinterpret_cast<T2 *>(p) where p is a pointer to *x* of type âpointer to T1â[.](#11.sentence-2)
|
||||
|
||||
[*Note [7](#note-7)*:
|
||||
|
||||
No temporary is materialized ([[conv.rval]](conv.rval "7.3.5 Temporary materialization conversion")) or created,
|
||||
no copy is made, and
|
||||
no constructors ([[class.ctor]](class.ctor "11.4.5 Constructors")) or conversion
|
||||
functions ([[class.conv]](class.conv "11.4.8 Conversions")) are called[.](#11.sentence-3)[55](#footnote-55 "This is sometimes referred to as a type pun when the result refers to the same object as the source glvalue.")
|
||||
|
||||
â *end note*]
|
||||
|
||||
[53)](#footnote-53)[53)](#footnoteref-53)
|
||||
|
||||
The
|
||||
types can have different cv-qualifiers, subject to
|
||||
the overall
|
||||
restriction that a reinterpret_cast cannot cast away constness[.](#footnote-53.sentence-1)
|
||||
|
||||
[54)](#footnote-54)[54)](#footnoteref-54)
|
||||
|
||||
T1 and T2 can have
|
||||
different cv-qualifiers, subject to
|
||||
the overall restriction that a reinterpret_cast cannot cast away
|
||||
constness[.](#footnote-54.sentence-1)
|
||||
|
||||
[55)](#footnote-55)[55)](#footnoteref-55)
|
||||
|
||||
This is sometimes referred to as a type pun
|
||||
when the result refers to the same object as the source glvalue[.](#footnote-55.sentence-1)
|
||||
124
cppdraft/expr/rel.md
Normal file
124
cppdraft/expr/rel.md
Normal file
@@ -0,0 +1,124 @@
|
||||
[expr.rel]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.rel)
|
||||
|
||||
### 7.6.9 Relational operators [expr.rel]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7404)
|
||||
|
||||
The relational operators group left-to-right[.](#1.sentence-1)
|
||||
|
||||
[*Example [1](#example-1)*:
|
||||
|
||||
a<b<c means (a<b)<c and not(a<b)&&(b<c)[.](#1.sentence-2)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[relational-expression:](#nt:relational-expression "7.6.9 Relational operators [expr.rel]")
|
||||
[*compare-expression*](expr.spaceship#nt:compare-expression "7.6.8 Three-way comparison operator [expr.spaceship]")
|
||||
[*relational-expression*](#nt:relational-expression "7.6.9 Relational operators [expr.rel]") < [*compare-expression*](expr.spaceship#nt:compare-expression "7.6.8 Three-way comparison operator [expr.spaceship]")
|
||||
[*relational-expression*](#nt:relational-expression "7.6.9 Relational operators [expr.rel]") > [*compare-expression*](expr.spaceship#nt:compare-expression "7.6.8 Three-way comparison operator [expr.spaceship]")
|
||||
[*relational-expression*](#nt:relational-expression "7.6.9 Relational operators [expr.rel]") <= [*compare-expression*](expr.spaceship#nt:compare-expression "7.6.8 Three-way comparison operator [expr.spaceship]")
|
||||
[*relational-expression*](#nt:relational-expression "7.6.9 Relational operators [expr.rel]") >= [*compare-expression*](expr.spaceship#nt:compare-expression "7.6.8 Three-way comparison operator [expr.spaceship]")
|
||||
|
||||
The
|
||||
lvalue-to-rvalue ([[conv.lval]](conv.lval "7.3.2 Lvalue-to-rvalue conversion"))
|
||||
and function-to-pointer ([[conv.func]](conv.func "7.3.4 Function-to-pointer conversion"))
|
||||
standard conversions are performed on the operands[.](#1.sentence-3)
|
||||
|
||||
If one of the operands is a pointer, the
|
||||
array-to-pointer conversion ([[conv.array]](conv.array "7.3.3 Array-to-pointer conversion")) is performed on the other operand[.](#1.sentence-4)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7435)
|
||||
|
||||
The converted operands shall have arithmetic, enumeration, or pointer type[.](#2.sentence-1)
|
||||
|
||||
The
|
||||
operators < (less than), > (greater than), <= (less than or equal to), and >= (greater than or equal to) all
|
||||
yield false or true[.](#2.sentence-2)
|
||||
|
||||
The type of the result isbool[.](#2.sentence-3)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7443)
|
||||
|
||||
The usual arithmetic conversions ([[expr.arith.conv]](expr.arith.conv "7.4 Usual arithmetic conversions")) are performed on operands of arithmetic
|
||||
or enumeration type[.](#3.sentence-1)
|
||||
|
||||
If both converted operands are pointers,
|
||||
pointer conversions ([[conv.ptr]](conv.ptr "7.3.12 Pointer conversions")),
|
||||
function pointer conversions ([[conv.fctptr]](conv.fctptr "7.3.14 Function pointer conversions")), and
|
||||
qualification conversions ([[conv.qual]](conv.qual "7.3.6 Qualification conversions"))
|
||||
are performed to bring
|
||||
them to their [composite pointer type](expr.type#def:composite_pointer_type "7.2.2 Type [expr.type]")[.](#3.sentence-2)
|
||||
|
||||
After conversions, the operands shall have the same type[.](#3.sentence-3)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7453)
|
||||
|
||||
The result of comparing unequal pointers to objects[65](#footnote-65 "As specified in [basic.compound], an object that is not an array element is considered to belong to a single-element array for this purpose and a pointer past the last element of an array of n elements is considered to be equivalent to a pointer to a hypothetical array element n for this purpose.") is defined in terms of a partial order consistent with the following rules:
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
If two pointers point to different elements of the same array, or to
|
||||
subobjects thereof, the pointer to the element with the higher subscript
|
||||
is required to compare greater[.](#4.1.sentence-1)
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
If two pointers point to different non-static data members of the same
|
||||
object, or to subobjects of such members, recursively,
|
||||
the pointer to the later declared member is required to compare greater provided
|
||||
neither member is a subobject of zero size
|
||||
and their class is not a union[.](#4.2.sentence-1)
|
||||
|
||||
- [(4.3)](#4.3)
|
||||
|
||||
Otherwise, neither pointer is required to compare greater than the other[.](#4.3.sentence-1)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7479)
|
||||
|
||||
If two operands p and q compare equal ([[expr.eq]](expr.eq "7.6.10 Equality operators")),p<=q and p>=q both yield true and p<q andp>q both yield false[.](#5.sentence-1)
|
||||
|
||||
Otherwise, if a pointer to object p compares greater than a pointer q, p>=q, p>q,q<=p, and q<p all yield true and p<=q,p<q, q>=p, and q>p all yield false[.](#5.sentence-2)
|
||||
|
||||
Otherwise, the result of each of the operators is unspecified[.](#5.sentence-3)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
A relational operator applied
|
||||
to unequal function pointers
|
||||
yields an unspecified result[.](#5.sentence-4)
|
||||
|
||||
A pointer value of type âpointer to cv voidâ
|
||||
can point to an object ([[basic.compound]](basic.compound "6.9.4 Compound types"))[.](#5.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7495)
|
||||
|
||||
If both operands (after conversions) are of arithmetic or enumeration type, each
|
||||
of the operators shall yield true if the specified relationship is true
|
||||
and false if it is false[.](#6.sentence-1)
|
||||
|
||||
[65)](#footnote-65)[65)](#footnoteref-65)
|
||||
|
||||
As specified in [[basic.compound]](basic.compound "6.9.4 Compound types"),
|
||||
an object that is not an array element
|
||||
is considered to belong to a
|
||||
single-element array for this purpose and
|
||||
a pointer past the last element of an array of n elements
|
||||
is considered to be equivalent to a pointer to a hypothetical array elementn for this purpose[.](#footnote-65.sentence-1)
|
||||
63
cppdraft/expr/shift.md
Normal file
63
cppdraft/expr/shift.md
Normal file
@@ -0,0 +1,63 @@
|
||||
[expr.shift]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.shift)
|
||||
|
||||
### 7.6.7 Shift operators [expr.shift]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7230)
|
||||
|
||||
The shift operators << and >> group left-to-right[.](#1.sentence-1)
|
||||
|
||||
[shift-expression:](#nt:shift-expression "7.6.7 Shift operators [expr.shift]")
|
||||
[*additive-expression*](expr.add#nt:additive-expression "7.6.6 Additive operators [expr.add]")
|
||||
[*shift-expression*](#nt:shift-expression "7.6.7 Shift operators [expr.shift]") << [*additive-expression*](expr.add#nt:additive-expression "7.6.6 Additive operators [expr.add]")
|
||||
[*shift-expression*](#nt:shift-expression "7.6.7 Shift operators [expr.shift]") >> [*additive-expression*](expr.add#nt:additive-expression "7.6.6 Additive operators [expr.add]")
|
||||
|
||||
The operands shall be prvalues of integral or unscoped enumeration type and integral
|
||||
promotions are performed[.](#1.sentence-2)
|
||||
|
||||
The type of the result is that of the promoted
|
||||
left operand[.](#1.sentence-3)
|
||||
|
||||
The behavior is undefined if the right operand is negative, or greater
|
||||
than or equal to the width of the promoted left operand[.](#1.sentence-4)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7258)
|
||||
|
||||
The value of E1 << E2 is the unique value congruent toE1Ã2E2 modulo 2N,
|
||||
where N is the width of the type of the result[.](#2.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
E1 is left-shifted E2 bit positions;
|
||||
vacated bits are zero-filled[.](#2.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7267)
|
||||
|
||||
The value of E1 >> E2 is E1/2E2,
|
||||
rounded towards negative infinity[.](#3.sentence-1)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
E1 is right-shifted E2 bit positions[.](#3.sentence-2)
|
||||
|
||||
Right-shift on signed integral types is an arithmetic right shift,
|
||||
which performs sign-extension[.](#3.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7276)
|
||||
|
||||
The expression E1 is sequenced before the expression E2[.](#4.sentence-1)
|
||||
116
cppdraft/expr/sizeof.md
Normal file
116
cppdraft/expr/sizeof.md
Normal file
@@ -0,0 +1,116 @@
|
||||
[expr.sizeof]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.sizeof)
|
||||
|
||||
### 7.6.2 Unary expressions [[expr.unary]](expr.unary#expr.sizeof)
|
||||
|
||||
#### 7.6.2.5 Sizeof [expr.sizeof]
|
||||
|
||||
[1](#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[.](#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]")[.](#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[.](#1.sentence-3)
|
||||
|
||||
The result of sizeof applied to any of the narrow character types is 1[.](#1.sentence-4)
|
||||
|
||||
The result ofsizeof applied to any other fundamental
|
||||
type ([[basic.fundamental]](basic.fundamental "6.9.2 Fundamental types")) is implementation-defined[.](#1.sentence-5)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
In particular, the values of sizeof(bool), sizeof(char16_t),sizeof(char32_t), and sizeof(wchar_t) are
|
||||
implementation-defined[.](#1.sentence-6)[57](#footnote-57 "sizeof(bool) is not required to be 1.")
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Note [2](#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[.](#1.sentence-7)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#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[.](#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[.](#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[.](#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[.](#2.sentence-4)
|
||||
|
||||
This implies that the size of an array of n elements isn times the size of an element[.](#2.sentence-5)
|
||||
|
||||
[3](#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[.](#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[.](#3.sentence-2)
|
||||
|
||||
[4](#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[.](#4.sentence-1)
|
||||
|
||||
The sizeof... operator yields the number of elements
|
||||
in the pack ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates"))[.](#4.sentence-2)
|
||||
|
||||
A sizeof... expression is a pack expansion ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates"))[.](#4.sentence-3)
|
||||
|
||||
[*Example [1](#example-1)*: template<class... Types>struct count {static constexpr std::size_t value = sizeof...(Types);}; â *end example*]
|
||||
|
||||
[5](#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[.](#5.sentence-1)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
A sizeof expression
|
||||
is an integral constant expression ([[expr.const]](expr.const "7.7 Constant expressions"))[.](#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"))[.](#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)
|
||||
124
cppdraft/expr/spaceship.md
Normal file
124
cppdraft/expr/spaceship.md
Normal file
@@ -0,0 +1,124 @@
|
||||
[expr.spaceship]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.spaceship)
|
||||
|
||||
### 7.6.8 Three-way comparison operator [expr.spaceship]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7283)
|
||||
|
||||
The three-way comparison operator groups left-to-right[.](#1.sentence-1)
|
||||
|
||||
[compare-expression:](#nt:compare-expression "7.6.8 Three-way comparison operator [expr.spaceship]")
|
||||
[*shift-expression*](expr.shift#nt:shift-expression "7.6.7 Shift operators [expr.shift]")
|
||||
[*compare-expression*](#nt:compare-expression "7.6.8 Three-way comparison operator [expr.spaceship]") <=> [*shift-expression*](expr.shift#nt:shift-expression "7.6.7 Shift operators [expr.shift]")
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7296)
|
||||
|
||||
The expression p <=> q is a prvalue indicating whetherp is less than, equal to, greater than, or incomparable withq[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7301)
|
||||
|
||||
If one of the operands is of type bool and the other is not, the program is ill-formed[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7305)
|
||||
|
||||
If both operands have arithmetic types,
|
||||
or one operand has integral type and
|
||||
the other operand has unscoped enumeration type,
|
||||
the [usual arithmetic conversions](expr.arith.conv "7.4 Usual arithmetic conversions [expr.arith.conv]") are applied to the operands[.](#4.sentence-1)
|
||||
|
||||
Then:
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
If a [narrowing conversion](dcl.init.list#def:conversion,narrowing "9.5.5 List-initialization [dcl.init.list]") is required,
|
||||
other than from an integral type to a floating-point type,
|
||||
the program is ill-formed[.](#4.1.sentence-1)
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
Otherwise, if the operands have integral type,
|
||||
the result is of type std::strong_ordering[.](#4.2.sentence-1)
|
||||
The result isstd::strong_ordering::equal if both operands are arithmetically equal,std::strong_ordering::less if the first operand is arithmetically
|
||||
less than the second operand,
|
||||
andstd::strong_ordering::greater otherwise[.](#4.2.sentence-2)
|
||||
|
||||
- [(4.3)](#4.3)
|
||||
|
||||
Otherwise, the operands have floating-point type, and
|
||||
the result is of type std::partial_ordering[.](#4.3.sentence-1)
|
||||
The expression a <=> b yieldsstd::partial_ordering::less if a is less than b,std::partial_ordering::greater if a is greater than b,std::partial_ordering::equivalent if a is equivalent to b,
|
||||
andstd::partial_ordering::unordered otherwise[.](#4.3.sentence-2)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7343)
|
||||
|
||||
If both operands have the same enumeration type E,
|
||||
the operator yields the result of
|
||||
converting the operands to the underlying type of E and applying <=> to the converted operands[.](#5.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7349)
|
||||
|
||||
If at least one of the operands is of object pointer type and
|
||||
the other operand is of object pointer or array type,
|
||||
array-to-pointer conversions ([[conv.array]](conv.array "7.3.3 Array-to-pointer conversion")),
|
||||
pointer conversions ([[conv.ptr]](conv.ptr "7.3.12 Pointer conversions")),
|
||||
and[qualification conversions](conv.qual "7.3.6 Qualification conversions [conv.qual]") are performed on both operands
|
||||
to bring them to their composite pointer type ([[expr.type]](expr.type "7.2.2 Type"))[.](#6.sentence-1)
|
||||
|
||||
After the conversions, the operands shall have the same type[.](#6.sentence-2)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
If both of the operands are arrays,[array-to-pointer conversions](conv.array "7.3.3 Array-to-pointer conversion [conv.array]") are not applied[.](#6.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
In this case,p <=> q is of type std::strong_ordering and
|
||||
the result is defined by the following rules:
|
||||
|
||||
- [(6.1)](#6.1)
|
||||
|
||||
If two pointer operands p and q compare equal ([[expr.eq]](expr.eq "7.6.10 Equality operators")),p <=> q yields std::strong_ordering::equal;
|
||||
|
||||
- [(6.2)](#6.2)
|
||||
|
||||
otherwise, if p and q compare unequal,p <=> q yieldsstd::strong_ordering::less if q compares greater than p andstd::strong_ordering::greater if p compares greater than q ([[expr.rel]](expr.rel "7.6.9 Relational operators"));
|
||||
|
||||
- [(6.3)](#6.3)
|
||||
|
||||
otherwise, the result is unspecified[.](#6.sentence-4)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7382)
|
||||
|
||||
Otherwise, the program is ill-formed[.](#7.sentence-1)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7385)
|
||||
|
||||
The three comparison category types ([[cmp.categories]](cmp.categories "17.12.2 Comparison category types"))
|
||||
(the typesstd::strong_ordering,std::weak_ordering, andstd::partial_ordering)
|
||||
are not predefined;
|
||||
if a standard library declaration ([[compare.syn]](compare.syn "17.12.1 Header <compare> synopsis"), [[std.modules]](std.modules "16.4.2.4 Modules"))
|
||||
of such a class type does not precede ([[basic.lookup.general]](basic.lookup.general "6.5.1 General"))
|
||||
a use of that type â
|
||||
even an implicit use in which the type is not named
|
||||
(e.g., via the auto specifier ([[dcl.spec.auto]](dcl.spec.auto "9.2.9.7 Placeholder type specifiers"))
|
||||
in a defaulted three-way comparison ([[class.spaceship]](class.spaceship "11.10.3 Three-way comparison"))
|
||||
or use of the built-in operator) â the program is ill-formed[.](#8.sentence-1)
|
||||
275
cppdraft/expr/static/cast.md
Normal file
275
cppdraft/expr/static/cast.md
Normal file
@@ -0,0 +1,275 @@
|
||||
[expr.static.cast]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.static.cast)
|
||||
|
||||
### 7.6.1 Postfix expressions [[expr.post]](expr.post#expr.static.cast)
|
||||
|
||||
#### 7.6.1.9 Static cast [expr.static.cast]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4658)
|
||||
|
||||
The result of the expression static_cast<T>(v) is the result of
|
||||
converting the expression v to type T[.](#1.sentence-1)
|
||||
|
||||
If T is an lvalue reference type
|
||||
or an rvalue reference to function type, the result is an lvalue;
|
||||
if T is an rvalue reference to object type, the result is an xvalue;
|
||||
otherwise, the result is a prvalue[.](#1.sentence-2)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4670)
|
||||
|
||||
An lvalue of type â*cv1* Bâ, where B is a class
|
||||
type, can be cast to type âreference to *cv2* Dâ, whereD is a complete class derived ([[class.derived]](class.derived "11.7 Derived classes")) from B,
|
||||
if *cv2* is the
|
||||
same cv-qualification as, or greater cv-qualification than,*cv1*[.](#2.sentence-1)
|
||||
|
||||
If B is a virtual base class of D or a base class of a virtual base class of D,
|
||||
or if no valid standard conversion from âpointer to Dâ
|
||||
to âpointer to Bâ exists ([[conv.ptr]](conv.ptr "7.3.12 Pointer conversions")), the program is ill-formed[.](#2.sentence-2)
|
||||
|
||||
An xvalue of type
|
||||
â*cv1* Bâ can be cast to type ârvalue reference to*cv2* Dâ with the same constraints as for an lvalue of
|
||||
type â*cv1* Bâ[.](#2.sentence-3)
|
||||
|
||||
If the object
|
||||
of type â*cv1* Bâ is actually a base class subobject of an object
|
||||
of type D, the result refers to the enclosing object of typeD[.](#2.sentence-4)
|
||||
|
||||
Otherwise, the behavior is undefined[.](#2.sentence-5)
|
||||
|
||||
[*Example [1](#example-1)*: struct B { };struct D : public B { };
|
||||
D d;
|
||||
B &br = d;
|
||||
|
||||
static_cast<D&>(br); // produces lvalue denoting the original d object â *end example*]
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4700)
|
||||
|
||||
An lvalue
|
||||
of type T1 can be cast to type ârvalue
|
||||
reference to T2â if T2 is reference-compatible withT1 ([[dcl.init.ref]](dcl.init.ref "9.5.4 References"))[.](#3.sentence-1)
|
||||
|
||||
If the value is not a bit-field,
|
||||
the result refers to the object or the specified base class subobject
|
||||
thereof; otherwise, the [lvalue-to-rvalue conversion](conv.lval "7.3.2 Lvalue-to-rvalue conversion [conv.lval]") is applied to the bit-field and the resulting prvalue is used as the
|
||||
operand of the static_cast for the remainder of this subclause[.](#3.sentence-2)
|
||||
|
||||
If T2 is an inaccessible ([[class.access]](class.access "11.8 Member access control")) or
|
||||
ambiguous ([[class.member.lookup]](class.member.lookup "6.5.2 Member name lookup")) base class of T1,
|
||||
a program that necessitates such a cast is ill-formed[.](#3.sentence-3)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4713)
|
||||
|
||||
Any expression can be explicitly converted to type cv void,
|
||||
in which case the operand is a discarded-value expression ([[expr.prop]](expr.prop "7.2 Properties of expressions"))[.](#4.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
Such a static_cast has no result
|
||||
as it is a prvalue of type void; see [[basic.lval]](basic.lval "7.2.1 Value category")[.](#4.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
However, if the value is in a temporary
|
||||
object ([[class.temporary]](class.temporary "6.8.7 Temporary objects")), the destructor for that
|
||||
object is
|
||||
not executed until the usual time, and the value of the object is
|
||||
preserved for the purpose of executing the destructor[.](#4.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4728)
|
||||
|
||||
Otherwise, an expression E can be explicitly converted to a type T if there is an implicit conversion sequence ([[over.best.ics]](over.best.ics "12.2.4.2 Implicit conversion sequences"))
|
||||
from E to T,
|
||||
if overload resolution for a direct-initialization ([[dcl.init]](dcl.init "9.5 Initializers"))
|
||||
of an object or reference of type T from E would find at least one viable function ([[over.match.viable]](over.match.viable "12.2.3 Viable functions")), or
|
||||
if T is an aggregate type ([[dcl.init.aggr]](dcl.init.aggr "9.5.2 Aggregates"))
|
||||
having a first element x and
|
||||
there is an implicit conversion sequence
|
||||
from E to the type of x[.](#5.sentence-1)
|
||||
|
||||
If T is a reference type, the effect is
|
||||
the same as performing the declaration and initializationT t(E); for some invented temporary variable t ([[dcl.init]](dcl.init "9.5 Initializers"))
|
||||
and then using the temporary variable as the result of the conversion[.](#5.sentence-2)
|
||||
|
||||
Otherwise, the result object is direct-initialized from E[.](#5.sentence-3)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
The conversion is ill-formed when attempting to convert an
|
||||
expression of class type to an inaccessible or ambiguous base class[.](#5.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Note [4](#note-4)*:
|
||||
|
||||
If T is âarray of unknown bound of Uâ,
|
||||
this direct-initialization defines the type of the expression as U[1][.](#5.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4756)
|
||||
|
||||
Otherwise, 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")) conversions are applied to the
|
||||
operand, and the conversions that can be performed using static_cast are listed below[.](#6.sentence-1)
|
||||
|
||||
No other conversion can be performed using static_cast[.](#6.sentence-2)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4763)
|
||||
|
||||
A value of a scoped enumeration type ([[dcl.enum]](dcl.enum "9.8.1 Enumeration declarations"))
|
||||
can be explicitly converted to an integral type;
|
||||
the result is the same as that of converting
|
||||
to the enumeration's underlying type and then to the destination type[.](#7.sentence-1)
|
||||
|
||||
A value of a scoped enumeration type
|
||||
can also be explicitly converted to a floating-point type;
|
||||
the result is the same as that of converting
|
||||
from the original value to the floating-point type[.](#7.sentence-2)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4773)
|
||||
|
||||
A value of integral or enumeration type can be explicitly converted to
|
||||
a complete enumeration type[.](#8.sentence-1)
|
||||
|
||||
If the enumeration type has a fixed underlying type,
|
||||
the value is first converted to that type
|
||||
by
|
||||
integral promotion ([[conv.prom]](conv.prom "7.3.7 Integral promotions")) or integral conversion ([[conv.integral]](conv.integral "7.3.9 Integral conversions")),
|
||||
if necessary, and
|
||||
then to the enumeration type[.](#8.sentence-2)
|
||||
|
||||
If the enumeration type does not have a fixed underlying type,
|
||||
the value is unchanged
|
||||
if the original value is within the range
|
||||
of the enumeration values ([[dcl.enum]](dcl.enum "9.8.1 Enumeration declarations")), and
|
||||
otherwise, the behavior is undefined[.](#8.sentence-3)
|
||||
|
||||
A value of floating-point type can also be explicitly converted to an enumeration type[.](#8.sentence-4)
|
||||
|
||||
The resulting value is the same as converting the original value to the
|
||||
underlying type of the enumeration ([[conv.fpint]](conv.fpint "7.3.11 Floating-integral conversions")), and subsequently to
|
||||
the enumeration type[.](#8.sentence-5)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4794)
|
||||
|
||||
A prvalue of floating-point type can be explicitly converted to
|
||||
any other floating-point type[.](#9.sentence-1)
|
||||
|
||||
If the source value can be exactly represented in the destination type,
|
||||
the result of the conversion has that exact representation[.](#9.sentence-2)
|
||||
|
||||
If the source value is between two adjacent destination values,
|
||||
the result of the conversion is
|
||||
an implementation-defined choice of
|
||||
either of those values[.](#9.sentence-3)
|
||||
|
||||
Otherwise, the behavior is undefined[.](#9.sentence-4)
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4805)
|
||||
|
||||
A prvalue of type âpointer to *cv1* Bâ, where B is a class type, can be converted to a prvalue of type âpointer to*cv2* Dâ,
|
||||
where D is a complete class[derived](class.derived "11.7 Derived classes [class.derived]") from B,
|
||||
if *cv2* is the same cv-qualification as,
|
||||
or greater cv-qualification than, *cv1*[.](#10.sentence-1)
|
||||
|
||||
If B is a virtual base class of D or
|
||||
a base class of a virtual base class of D, or
|
||||
if no valid standard conversion from âpointer to Dâ
|
||||
to âpointer to Bâ exists ([[conv.ptr]](conv.ptr "7.3.12 Pointer conversions")), the program is ill-formed[.](#10.sentence-2)
|
||||
|
||||
The null pointer value ([[basic.compound]](basic.compound "6.9.4 Compound types")) is converted
|
||||
to the null pointer value of the destination type[.](#10.sentence-3)
|
||||
|
||||
If the prvalue of type
|
||||
âpointer to *cv1* Bâ points to a B that is
|
||||
actually a base class subobject of an object of type D, the resulting
|
||||
pointer points to the enclosing object of type D[.](#10.sentence-4)
|
||||
|
||||
Otherwise, the
|
||||
behavior is undefined[.](#10.sentence-5)
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4827)
|
||||
|
||||
A prvalue of type âpointer to member of D of type *cv1*Tâ can be converted to a prvalue of type âpointer to member ofB of type *cv2* Tâ, whereD is a complete class type andB is a [base class](class.derived "11.7 Derived classes [class.derived]") of D,
|
||||
if *cv2* is the same cv-qualification
|
||||
as, or greater cv-qualification than, *cv1*[.](#11.sentence-1)
|
||||
|
||||
[*Note [5](#note-5)*:
|
||||
|
||||
Function types (including those used in pointer-to-member-function types)
|
||||
are never cv-qualified ([[dcl.fct]](dcl.fct "9.3.4.6 Functions"))[.](#11.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
If no valid standard conversion
|
||||
from âpointer to member of B of type Tâ
|
||||
to âpointer to member of D of type Tâ
|
||||
exists ([[conv.mem]](conv.mem "7.3.13 Pointer-to-member conversions")), the program is ill-formed[.](#11.sentence-3)
|
||||
|
||||
The [null member pointer value](conv.mem#def:value,null_member_pointer "7.3.13 Pointer-to-member conversions [conv.mem]") is converted to the null
|
||||
member pointer value of the destination type[.](#11.sentence-4)
|
||||
|
||||
If class B contains the original member, or is a base class of the class
|
||||
containing the original member, the resulting pointer to member points
|
||||
to the original member[.](#11.sentence-5)
|
||||
|
||||
Otherwise, the behavior is undefined[.](#11.sentence-6)
|
||||
|
||||
[*Note [6](#note-6)*:
|
||||
|
||||
Although class B need not contain the original member, the
|
||||
dynamic type of the object with which indirection through the pointer
|
||||
to member is performed must contain the original member;
|
||||
see [[expr.mptr.oper]](expr.mptr.oper "7.6.4 Pointer-to-member operators")[.](#11.sentence-7)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4856)
|
||||
|
||||
A prvalue of type âpointer to *cv1* voidâ can be
|
||||
converted to a prvalue of type âpointer to *cv2* Tâ,
|
||||
where T is an object type and *cv2* is the same
|
||||
cv-qualification as, or greater cv-qualification than, *cv1*[.](#12.sentence-1)
|
||||
|
||||
If the original pointer value represents the addressA of a byte in memory andA does not satisfy the alignment requirement of T,
|
||||
then the resulting pointer value ([[basic.compound]](basic.compound "6.9.4 Compound types")) is unspecified[.](#12.sentence-2)
|
||||
|
||||
Otherwise, if the original pointer value points to an object *a*,
|
||||
and there is an object *b* of type similar to T that is [pointer-interconvertible](basic.compound#def:pointer-interconvertible "6.9.4 Compound types [basic.compound]") with *a*,
|
||||
the result is a pointer to *b*[.](#12.sentence-3)
|
||||
|
||||
Otherwise, the pointer value is unchanged by the conversion[.](#12.sentence-4)
|
||||
|
||||
[*Example [2](#example-2)*: T* p1 = new T;const T* p2 = static_cast<const T*>(static_cast<void*>(p1));bool b = p1 == p2; // b will have the value true. â *end example*]
|
||||
66
cppdraft/expr/sub.md
Normal file
66
cppdraft/expr/sub.md
Normal file
@@ -0,0 +1,66 @@
|
||||
[expr.sub]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.sub)
|
||||
|
||||
### 7.6.1 Postfix expressions [[expr.post]](expr.post#expr.sub)
|
||||
|
||||
#### 7.6.1.2 Subscripting [expr.sub]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3701)
|
||||
|
||||
A [*subscript expression*](#def:expression,subscript "7.6.1.2 Subscripting [expr.sub]") is a postfix expression
|
||||
followed by square brackets containing
|
||||
a possibly empty, comma-separated list of [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1 General [dcl.init.general]")*s* that constitute the arguments to the subscript operator[.](#1.sentence-1)
|
||||
|
||||
The [*postfix-expression*](expr.post.general#nt:postfix-expression "7.6.1.1 General [expr.post.general]") and
|
||||
the initialization of the object parameter ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")) of
|
||||
any applicable subscript operator function ([[over.sub]](over.sub "12.4.5 Subscripting")) is sequenced before
|
||||
each expression in the [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") and also before
|
||||
any default argument ([[dcl.fct.default]](dcl.fct.default "9.3.4.7 Default arguments"))[.](#1.sentence-2)
|
||||
|
||||
The initialization of a non-object parameter of
|
||||
a subscript operator function S,
|
||||
including every associated value computation and side effect,
|
||||
is indeterminately sequenced with respect to that of
|
||||
any other non-object parameter of S[.](#1.sentence-3)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3719)
|
||||
|
||||
With the built-in subscript operator,
|
||||
an [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") shall be present,
|
||||
consisting of a single [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment and compound assignment operators [expr.assign]")[.](#2.sentence-1)
|
||||
|
||||
One of the expressions shall be a glvalue of type âarray ofTâ or a prvalue of type âpointer
|
||||
to Tâ and the other shall be a prvalue of unscoped enumeration or integral type[.](#2.sentence-2)
|
||||
|
||||
The result is of type âTâ[.](#2.sentence-3)
|
||||
|
||||
The type âTâ shall be a completely-defined object type[.](#2.sentence-4)[48](#footnote-48 "This is true even if the subscript operator is used in the following common idiom: &x[0].")
|
||||
|
||||
The expression E1[E2] is identical (by definition) to*((E1)+(E2)),
|
||||
except that in the case of an array operand, the result is an lvalue
|
||||
if that operand is an lvalue and an xvalue otherwise[.](#2.sentence-5)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L3739)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
Despite its asymmetric appearance, subscripting is a commutative
|
||||
operation except for sequencing[.](#3.sentence-1)
|
||||
|
||||
See [[expr.unary]](expr.unary "7.6.2 Unary expressions") and [[expr.add]](expr.add "7.6.6 Additive operators") for details of * and+ and [[dcl.array]](dcl.array "9.3.4.5 Arrays") for details of array types[.](#3.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[48)](#footnote-48)[48)](#footnoteref-48)
|
||||
|
||||
This
|
||||
is true even if the subscript operator is used in the following common idiom:&x[0][.](#footnote-48.sentence-1)
|
||||
54
cppdraft/expr/throw.md
Normal file
54
cppdraft/expr/throw.md
Normal file
@@ -0,0 +1,54 @@
|
||||
[expr.throw]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.throw)
|
||||
|
||||
### 7.6.18 Throwing an exception [expr.throw]
|
||||
|
||||
[throw-expression:](#nt:throw-expression "7.6.18 Throwing an exception [expr.throw]")
|
||||
throw [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment and compound assignment operators [expr.assign]")opt
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8025)
|
||||
|
||||
A [*throw-expression*](#nt:throw-expression "7.6.18 Throwing an exception [expr.throw]") is of type void[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8028)
|
||||
|
||||
A [*throw-expression*](#nt:throw-expression "7.6.18 Throwing an exception [expr.throw]") with an operand throws an
|
||||
exception ([[except.throw]](except.throw "14.2 Throwing an exception"))[.](#2.sentence-1)
|
||||
|
||||
The 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 performed on the operand[.](#2.sentence-2)
|
||||
|
||||
The type of the exception object is determined by removing
|
||||
any top-level [*cv-qualifier*](dcl.decl.general#nt:cv-qualifier "9.3.1 General [dcl.decl.general]")*s* from the type of the
|
||||
(possibly converted) operand[.](#2.sentence-3)
|
||||
|
||||
The exception object is copy-initialized ([[dcl.init.general]](dcl.init.general "9.5.1 General"))
|
||||
from the (possibly converted) operand[.](#2.sentence-4)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8039)
|
||||
|
||||
A[*throw-expression*](#nt:throw-expression "7.6.18 Throwing an exception [expr.throw]") with no operand rethrows the currently handled exception ([[except.handle]](except.handle "14.4 Handling an exception"))[.](#3.sentence-1)
|
||||
|
||||
If no exception is presently being handled,
|
||||
the function std::terminate is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#3.sentence-2)
|
||||
|
||||
Otherwise, the exception is reactivated with the existing exception object;
|
||||
no new exception object is created[.](#3.sentence-3)
|
||||
|
||||
The exception is no longer considered to be caught[.](#3.sentence-4)
|
||||
|
||||
[*Example [1](#example-1)*:
|
||||
|
||||
An exception handler that cannot completely handle the exception itself
|
||||
can be written like this:try {// ...} catch (...) { // catch all exceptions// respond (partially) to exceptionthrow; // pass the exception to some other handler}
|
||||
|
||||
â *end example*]
|
||||
110
cppdraft/expr/type.md
Normal file
110
cppdraft/expr/type.md
Normal file
@@ -0,0 +1,110 @@
|
||||
[expr.type]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.2 Properties of expressions [[expr.prop]](expr.prop#expr.type)
|
||||
|
||||
### 7.2.2 Type [expr.type]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L335)
|
||||
|
||||
If an expression initially has the type âreference toTâ ([[dcl.ref]](dcl.ref "9.3.4.3 References"), [[dcl.init.ref]](dcl.init.ref "9.5.4 References")), the type is adjusted toT prior to any further analysis;
|
||||
the value category of the expression is not altered[.](#1.sentence-1)
|
||||
|
||||
Let X be the object or function denoted by the reference[.](#1.sentence-2)
|
||||
|
||||
If a pointer to X would be valid in
|
||||
the context of the evaluation of the expression ([[basic.fundamental]](basic.fundamental "6.9.2 Fundamental types")),
|
||||
the result designates X;
|
||||
otherwise, the behavior is undefined[.](#1.sentence-3)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
Before the lifetime of the reference has started or after it has ended,
|
||||
the behavior is undefined (see [[basic.life]](basic.life "6.8.4 Lifetime"))[.](#1.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L351)
|
||||
|
||||
If a prvalue initially has the type âcv Tâ, whereT is a cv-unqualified non-class, non-array type, the type of
|
||||
the expression is adjusted to T prior to any further analysis[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L356)
|
||||
|
||||
The [*composite pointer type*](#def:composite_pointer_type "7.2.2 Type [expr.type]") of
|
||||
two operands p1 andp2 having types T1 and T2, respectively, where at least one is a
|
||||
pointer or pointer-to-member type orstd::nullptr_t, is:
|
||||
|
||||
- [(3.1)](#3.1)
|
||||
|
||||
if both p1 and p2 are null pointer constants,std::nullptr_t;
|
||||
|
||||
- [(3.2)](#3.2)
|
||||
|
||||
if either p1 or p2 is a null pointer constant, T2 or T1,
|
||||
respectively;
|
||||
|
||||
- [(3.3)](#3.3)
|
||||
|
||||
if T1 or T2 is âpointer to *cv1* voidâ and the
|
||||
other type is âpointer to *cv2* Tâ,
|
||||
where T is an object type or void,
|
||||
âpointer to *cv12* voidâ,
|
||||
where *cv12* is the union of *cv1* and *cv2*;
|
||||
|
||||
- [(3.4)](#3.4)
|
||||
|
||||
if T1 or T2 is âpointer to noexcept functionâ and the
|
||||
other type is âpointer to functionâ, where the function types are otherwise the same,
|
||||
âpointer to functionâ;
|
||||
|
||||
- [(3.5)](#3.5)
|
||||
|
||||
if T1 is âpointer to C1â and T2 is âpointer toC2â, where C1 is reference-related to C2 or C2 is
|
||||
reference-related to C1 ([[dcl.init.ref]](dcl.init.ref "9.5.4 References")),
|
||||
the qualification-combined type ([[conv.qual]](conv.qual "7.3.6 Qualification conversions"))
|
||||
of T1 and T2 or the qualification-combined type of T2 and T1,
|
||||
respectively;
|
||||
|
||||
- [(3.6)](#3.6)
|
||||
|
||||
if T1 or T2 is
|
||||
âpointer to member of C1 of type functionâ,
|
||||
the other type is
|
||||
âpointer to member of C2 of type noexcept functionâ, andC1 is reference-related to C2 orC2 is reference-related to C1 ([[dcl.init.ref]](dcl.init.ref "9.5.4 References")),
|
||||
where the function types are otherwise the same,
|
||||
âpointer to member of C2 of type functionâ or
|
||||
âpointer to member of C1 of type functionâ, respectively;
|
||||
|
||||
- [(3.7)](#3.7)
|
||||
|
||||
if T1 is
|
||||
âpointer to member of C1 of type *cv1* Uâ andT2 is
|
||||
âpointer to member of C2 of type *cv2* Uâ,
|
||||
for some non-function type U,
|
||||
where C1 is
|
||||
reference-related to C2 or C2 is reference-related toC1 ([[dcl.init.ref]](dcl.init.ref "9.5.4 References")), the qualification-combined type of T2 and T1 or the qualification-combined type
|
||||
of T1 and T2, respectively;
|
||||
|
||||
- [(3.8)](#3.8)
|
||||
|
||||
if T1 and T2 are similar types ([[conv.qual]](conv.qual "7.3.6 Qualification conversions")), the qualification-combined type of T1 andT2;
|
||||
|
||||
- [(3.9)](#3.9)
|
||||
|
||||
otherwise, a program that necessitates the determination of a
|
||||
composite pointer type is ill-formed[.](#3.sentence-1)
|
||||
|
||||
[*Example [1](#example-1)*: typedef void *p;typedef const int *q;typedef int **pi;typedef const int **pci;
|
||||
|
||||
The composite pointer type of p and q is âpointer to const voidâ; the
|
||||
composite pointer type of pi and pci is âpointer to const pointer toconst intâ[.](#3.sentence-2)
|
||||
|
||||
â *end example*]
|
||||
67
cppdraft/expr/type/conv.md
Normal file
67
cppdraft/expr/type/conv.md
Normal file
@@ -0,0 +1,67 @@
|
||||
[expr.type.conv]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.type.conv)
|
||||
|
||||
### 7.6.1 Postfix expressions [[expr.post]](expr.post#expr.type.conv)
|
||||
|
||||
#### 7.6.1.4 Explicit type conversion (functional notation) [expr.type.conv]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4051)
|
||||
|
||||
A [](dcl.type.simple "9.2.9.3 Simple type specifiers [dcl.type.simple]")[*simple-type-specifier*](dcl.type.simple#nt:simple-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") or[](temp.res "13.8 Name resolution [temp.res]")[*typename-specifier*](temp.res.general#nt:typename-specifier "13.8.1 General [temp.res.general]") followed
|
||||
by a parenthesized optional [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") or
|
||||
by a [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]") (the initializer)
|
||||
constructs a value of the specified type
|
||||
given the initializer[.](#1.sentence-1)
|
||||
|
||||
If the type is a placeholder
|
||||
for a deduced class type,
|
||||
it is replaced by the return type
|
||||
of the function selected by overload resolution
|
||||
for [class template deduction](over.match.class.deduct "12.2.2.9 Class template argument deduction [over.match.class.deduct]") for the remainder of this subclause[.](#1.sentence-2)
|
||||
|
||||
Otherwise, if the type contains a placeholder type,
|
||||
it is replaced by the type
|
||||
determined by placeholder type deduction ([[dcl.type.auto.deduct]](dcl.type.auto.deduct "9.2.9.7.2 Placeholder type deduction"))[.](#1.sentence-3)
|
||||
|
||||
Let T denote the resulting type[.](#1.sentence-4)
|
||||
|
||||
Then:
|
||||
|
||||
- [(1.1)](#1.1)
|
||||
|
||||
If the initializer is a parenthesized single expression,
|
||||
the type conversion expression is equivalent
|
||||
to the corresponding cast
|
||||
expression ([[expr.cast]](expr.cast "7.6.3 Explicit type conversion (cast notation)"))[.](#1.1.sentence-1)
|
||||
|
||||
- [(1.2)](#1.2)
|
||||
|
||||
Otherwise, if T is cv void,
|
||||
the initializer shall be () or {} (after pack expansion, if any), and
|
||||
the expression is a prvalue of type void that performs no initialization[.](#1.2.sentence-1)
|
||||
|
||||
- [(1.3)](#1.3)
|
||||
|
||||
Otherwise, if T is a reference type,
|
||||
the expression has the same effect as
|
||||
direct-initializing an invented variable t of type T from
|
||||
the initializer and then
|
||||
using t as the result of the expression;
|
||||
the result is an lvalue ifT is an lvalue reference type or
|
||||
an rvalue reference to function type and
|
||||
an xvalue otherwise[.](#1.3.sentence-1)
|
||||
|
||||
- [(1.4)](#1.4)
|
||||
|
||||
Otherwise,
|
||||
the expression is a prvalue of type T whose result object is direct-initialized ([[dcl.init]](dcl.init "9.5 Initializers"))
|
||||
with the initializer[.](#1.4.sentence-1)
|
||||
|
||||
If the initializer is a parenthesized optional [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]"),T shall not be an array type[.](#1.sentence-6)
|
||||
|
||||
[*Example [1](#example-1)*: struct A {};void f(A&); // #1void f(A&&); // #2 A& g();void h() { f(g()); // calls #1 f(A(g())); // calls #2 with a temporary object f(auto(g())); // calls #2 with a temporary object} â *end example*]
|
||||
125
cppdraft/expr/typeid.md
Normal file
125
cppdraft/expr/typeid.md
Normal file
@@ -0,0 +1,125 @@
|
||||
[expr.typeid]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.typeid)
|
||||
|
||||
### 7.6.1 Postfix expressions [[expr.post]](expr.post#expr.typeid)
|
||||
|
||||
#### 7.6.1.8 Type identification [expr.typeid]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4555)
|
||||
|
||||
The result of a typeid expression is an lvalue of static typeconst std::type_info ([[type.info]](type.info "17.7.3 Class type_info")) and dynamic type conststd::type_info or const *name* where *name* is animplementation-defined class publicly derived fromstd::type_info which preserves the behavior described
|
||||
in [[type.info]](type.info "17.7.3 Class type_info")[.](#1.sentence-1)[52](#footnote-52 "The recommended name for such a class is extended_type_info.")
|
||||
|
||||
The lifetime of the object referred to by the lvalue extends to the end
|
||||
of the program[.](#1.sentence-2)
|
||||
|
||||
Whether or not the destructor is called for thestd::type_info object at the end of the program is unspecified[.](#1.sentence-3)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4574)
|
||||
|
||||
If the type of the [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") or [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") operand is
|
||||
a (possibly cv-qualified) class type or
|
||||
a reference to (possibly cv-qualified) class type,
|
||||
that class shall be completely defined[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4580)
|
||||
|
||||
If an [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") operand of typeid is
|
||||
a possibly-parenthesized [*unary-expression*](expr.unary.general#nt:unary-expression "7.6.2.1 General [expr.unary.general]") whose [*unary-operator*](expr.unary.general#nt:unary-operator "7.6.2.1 General [expr.unary.general]") is * and
|
||||
whose operand evaluates to a null pointer value ([[basic.compound]](basic.compound "6.9.4 Compound types")),
|
||||
the typeid expression throws an exception ([[except.throw]](except.throw "14.2 Throwing an exception"))
|
||||
of a type that would match a handler of typestd::bad_typeid ([[bad.typeid]](bad.typeid "17.7.5 Class bad_typeid"))[.](#3.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
In other contexts, evaluating such a [*unary-expression*](expr.unary.general#nt:unary-expression "7.6.2.1 General [expr.unary.general]") results in undefined behavior ([[expr.unary.op]](expr.unary.op "7.6.2.2 Unary operators"))[.](#3.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4595)
|
||||
|
||||
When typeid is applied to a glvalue whose type is a
|
||||
polymorphic class type ([[class.virtual]](class.virtual "11.7.3 Virtual functions")), the result refers to astd::type_info object representing the type of the most derived
|
||||
object ([[intro.object]](intro.object "6.8.2 Object model")) (that is, the dynamic type) to which the
|
||||
glvalue refers[.](#4.sentence-1)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4602)
|
||||
|
||||
When typeid is applied to an expression other than a glvalue of
|
||||
a polymorphic class type, the result refers to a std::type_info object representing the static type of the expression[.](#5.sentence-1)
|
||||
|
||||
[Lvalue-to-rvalue](conv.lval "7.3.2 Lvalue-to-rvalue conversion [conv.lval]"), [array-to-pointer](conv.array "7.3.3 Array-to-pointer conversion [conv.array]"),
|
||||
and [function-to-pointer](conv.func "7.3.4 Function-to-pointer conversion [conv.func]") conversions are not applied to
|
||||
the expression[.](#5.sentence-2)
|
||||
|
||||
If the expression is a prvalue,
|
||||
the [temporary materialization conversion](conv.rval "7.3.5 Temporary materialization conversion [conv.rval]") is applied[.](#5.sentence-3)
|
||||
|
||||
The expression is an [unevaluated operand](expr.context#def:unevaluated_operand "7.2.3 Context dependence [expr.context]")[.](#5.sentence-4)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4614)
|
||||
|
||||
When typeid is applied to a [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]"), the result
|
||||
refers to a std::type_info object representing the type of the[*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]")[.](#6.sentence-1)
|
||||
|
||||
If the type of the [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") is a reference
|
||||
to a possibly cv-qualified type, the result of thetypeid expression refers to a std::type_info object
|
||||
representing the cv-unqualified referenced type[.](#6.sentence-2)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
The [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") cannot denote a function type with
|
||||
a [*cv-qualifier-seq*](dcl.decl.general#nt:cv-qualifier-seq "9.3.1 General [dcl.decl.general]") or a [*ref-qualifier*](dcl.decl.general#nt:ref-qualifier "9.3.1 General [dcl.decl.general]") ([[dcl.fct]](dcl.fct "9.3.4.6 Functions"))[.](#6.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4626)
|
||||
|
||||
If the type of the expression or [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") is a
|
||||
cv-qualified type, the result of the typeid expression refers
|
||||
to a std::type_info object representing the cv-unqualified
|
||||
type[.](#7.sentence-1)
|
||||
|
||||
[*Example [1](#example-1)*: class D { /* ... */ };
|
||||
D d1;const D d2;
|
||||
|
||||
typeid(d1) == typeid(d2); // yields truetypeid(D) == typeid(const D); // yields truetypeid(D) == typeid(d2); // yields truetypeid(D) == typeid(const D&); // yields true â *end example*]
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4644)
|
||||
|
||||
The type std::type_info ([[type.info]](type.info "17.7.3 Class type_info")) is not predefined;
|
||||
if a standard library declaration ([[typeinfo.syn]](typeinfo.syn "17.7.2 Header <typeinfo> synopsis"), [[std.modules]](std.modules "16.4.2.4 Modules")) ofstd::type_info does not precede ([[basic.lookup.general]](basic.lookup.general "6.5.1 General"))
|
||||
a typeid expression, the program is ill-formed[.](#8.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L4650)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
Subclause [[class.cdtor]](class.cdtor "11.9.5 Construction and destruction") describes the behavior of typeid applied to an object under construction or destruction[.](#9.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[52)](#footnote-52)[52)](#footnoteref-52)
|
||||
|
||||
The recommended name for such a class isextended_type_info[.](#footnote-52.sentence-1)
|
||||
1823
cppdraft/expr/unary.md
Normal file
1823
cppdraft/expr/unary.md
Normal file
File diff suppressed because it is too large
Load Diff
33
cppdraft/expr/unary/general.md
Normal file
33
cppdraft/expr/unary/general.md
Normal file
@@ -0,0 +1,33 @@
|
||||
[expr.unary.general]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.unary.general)
|
||||
|
||||
### 7.6.2 Unary expressions [[expr.unary]](expr.unary#general)
|
||||
|
||||
#### 7.6.2.1 General [expr.unary.general]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5167)
|
||||
|
||||
Expressions with unary operators group right-to-left[.](#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*](expr.await#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*](expr.unary.noexcept#nt:noexcept-expression "7.6.2.7 noexcept operator [expr.unary.noexcept]")
|
||||
[*new-expression*](expr.new#nt:new-expression "7.6.2.8 New [expr.new]")
|
||||
[*delete-expression*](expr.delete#nt:delete-expression "7.6.2.9 Delete [expr.delete]")
|
||||
[*reflect-expression*](expr.reflect#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
|
||||
* & + - ! ~
|
||||
37
cppdraft/expr/unary/noexcept.md
Normal file
37
cppdraft/expr/unary/noexcept.md
Normal file
@@ -0,0 +1,37 @@
|
||||
[expr.unary.noexcept]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.unary.noexcept)
|
||||
|
||||
### 7.6.2 Unary expressions [[expr.unary]](expr.unary#noexcept)
|
||||
|
||||
#### 7.6.2.7 noexcept operator [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](#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"))[.](#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[.](#1.sentence-2)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5739)
|
||||
|
||||
The result of the noexcept operator is a prvalue of type bool[.](#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[.](#2.sentence-2)
|
||||
|
||||
[*Note [1](#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"))[.](#2.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
224
cppdraft/expr/unary/op.md
Normal file
224
cppdraft/expr/unary/op.md
Normal file
@@ -0,0 +1,224 @@
|
||||
[expr.unary.op]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.unary.op)
|
||||
|
||||
### 7.6.2 Unary expressions [[expr.unary]](expr.unary#op)
|
||||
|
||||
#### 7.6.2.2 Unary operators [expr.unary.op]
|
||||
|
||||
[1](#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]")[.](#1.sentence-1)
|
||||
|
||||
Its operand shall be a prvalue of type âpointer to Tâ,
|
||||
where T is an object or function type[.](#1.sentence-2)
|
||||
|
||||
The operator yields an lvalue of type T[.](#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")[.](#1.sentence-4)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
Indirection through a pointer to an out-of-lifetime object is valid ([[basic.life]](basic.life "6.8.4 Lifetime"))[.](#1.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
Indirection through a pointer to an incomplete type (other thancv void) is valid[.](#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")[.](#1.sentence-7)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5241)
|
||||
|
||||
Each of the following unary operators yields a prvalue[.](#2.sentence-1)
|
||||
|
||||
[3](#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[.](#3.sentence-1)
|
||||
|
||||
- [(3.1)](#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[.](#3.1.sentence-1)
|
||||
The result has type âpointer to member of class C of type Tâ
|
||||
and designates C::m[.](#3.1.sentence-2)
|
||||
[*Note [3](#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[.](#3.1.sentence-3)
|
||||
â *end note*]
|
||||
|
||||
- [(3.2)](#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"))[.](#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]")[.](#3.2.sentence-2)
|
||||
[*Note [4](#note-4)*:
|
||||
In particular, taking the address of a variable of type âcv Tâ
|
||||
yields a pointer of type âpointer to cv Tâ[.](#3.2.sentence-3)
|
||||
â *end note*]
|
||||
|
||||
[*Example [1](#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](#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[.](#3.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[4](#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[.](#4.sentence-1)
|
||||
|
||||
[*Note [6](#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â[.](#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"))[.](#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[.](#4.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#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[.](#5.sentence-1)
|
||||
|
||||
The operand of & shall not be a bit-field[.](#5.sentence-2)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5315)
|
||||
|
||||
[*Note [7](#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"))[.](#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â[.](#6.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[7](#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[.](#7.sentence-1)
|
||||
|
||||
Integral promotion is performed on integral or enumeration
|
||||
operands[.](#7.sentence-2)
|
||||
|
||||
The type of the result is the type of the promoted operand[.](#7.sentence-3)
|
||||
|
||||
[8](#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[.](#8.sentence-1)
|
||||
|
||||
Integral
|
||||
promotion is performed on integral or enumeration operands[.](#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[.](#8.sentence-3)
|
||||
|
||||
The type of the
|
||||
result is the type of the promoted operand[.](#8.sentence-4)
|
||||
|
||||
[*Note [8](#note-8)*:
|
||||
|
||||
The result is the two's complement of the operand
|
||||
(where operand and result are considered as unsigned)[.](#8.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[9](#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[.](#9.sentence-1)
|
||||
|
||||
The type of the result is bool[.](#9.sentence-2)
|
||||
|
||||
[10](#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[.](#10.sentence-1)
|
||||
|
||||
Integral promotions are performed[.](#10.sentence-2)
|
||||
|
||||
The type of the result is the type of the promoted operand[.](#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[.](#10.sentence-4)
|
||||
|
||||
[*Note [9](#note-9)*:
|
||||
|
||||
The result is the ones' complement of the operand
|
||||
(where operand and result are considered as unsigned)[.](#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]")[.](#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[.](#10.sentence-7)
|
||||
|
||||
[*Note [10](#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[.](#10.sentence-8)
|
||||
|
||||
â *end note*]
|
||||
32
cppdraft/expr/xor.md
Normal file
32
cppdraft/expr/xor.md
Normal file
@@ -0,0 +1,32 @@
|
||||
[expr.xor]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.xor)
|
||||
|
||||
### 7.6.12 Bitwise exclusive OR operator [expr.xor]
|
||||
|
||||
[exclusive-or-expression:](#nt:exclusive-or-expression "7.6.12 Bitwise exclusive OR operator [expr.xor]")
|
||||
[*and-expression*](expr.bit.and#nt:and-expression "7.6.11 Bitwise AND operator [expr.bit.and]")
|
||||
[*exclusive-or-expression*](#nt:exclusive-or-expression "7.6.12 Bitwise exclusive OR operator [expr.xor]") ^ [*and-expression*](expr.bit.and#nt:and-expression "7.6.11 Bitwise AND operator [expr.bit.and]")
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7693)
|
||||
|
||||
The ^ operator groups left-to-right[.](#1.sentence-1)
|
||||
|
||||
The operands shall be of integral or unscoped enumeration type[.](#1.sentence-2)
|
||||
|
||||
The usual arithmetic conversions ([[expr.arith.conv]](expr.arith.conv "7.4 Usual arithmetic conversions")) are performed[.](#1.sentence-3)
|
||||
|
||||
Given the coefficients xi and yi of the base-2 representation ([[basic.fundamental]](basic.fundamental "6.9.2 Fundamental types"))
|
||||
of the converted operands x and y,
|
||||
the coefficient ri of the base-2 representation of the result r is 1 if either (but not both) of xi and yi is 1,
|
||||
and 0 otherwise[.](#1.sentence-4)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
The result is the bitwise exclusive or function of the operands[.](#1.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
28
cppdraft/expr/yield.md
Normal file
28
cppdraft/expr/yield.md
Normal file
@@ -0,0 +1,28 @@
|
||||
[expr.yield]
|
||||
|
||||
# 7 Expressions [[expr]](./#expr)
|
||||
|
||||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.yield)
|
||||
|
||||
### 7.6.17 Yielding a value [expr.yield]
|
||||
|
||||
[yield-expression:](#nt:yield-expression "7.6.17 Yielding a value [expr.yield]")
|
||||
co_yield [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment and compound assignment operators [expr.assign]")
|
||||
co_yield [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]")
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L7971)
|
||||
|
||||
A [*yield-expression*](#nt:yield-expression "7.6.17 Yielding a value [expr.yield]") shall appear only within a suspension context
|
||||
of a function ([[expr.await]](expr.await "7.6.2.4 Await"))[.](#1.sentence-1)
|
||||
|
||||
Let *e* be the operand of the [*yield-expression*](#nt:yield-expression "7.6.17 Yielding a value [expr.yield]") and*p* be an lvalue naming the promise object of the enclosing
|
||||
coroutine ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4 Coroutine definitions")), then the [*yield-expression*](#nt:yield-expression "7.6.17 Yielding a value [expr.yield]") is equivalent to the expressionco_await *p*.yield_value(*e*)[.](#1.sentence-2)
|
||||
|
||||
[*Example [1](#example-1)*: template <typename T>struct my_generator {struct promise_type { T current_value; /* ... */auto yield_value(T v) { current_value = std::move(v); return std::suspend_always{}; }}; struct iterator { /* ... */ };
|
||||
iterator begin();
|
||||
iterator end();};
|
||||
|
||||
my_generator<pair<int,int>> g1() {for (int i = 0; i < 10; ++i) co_yield {i,i};} my_generator<pair<int,int>> g2() {for (int i = 0; i < 10; ++i) co_yield make_pair(i,i);}auto f(int x = co_yield 5); // error: [*yield-expression*](#nt:yield-expression "7.6.17 Yielding a value [expr.yield]") outside of function suspension contextint a[] = { co_yield 1 }; // error: [*yield-expression*](#nt:yield-expression "7.6.17 Yielding a value [expr.yield]") outside of function suspension contextint main() {auto r1 = g1(); auto r2 = g2();
|
||||
assert(std::equal(r1.begin(), r1.end(), r2.begin(), r2.end()));} â *end example*]
|
||||
Reference in New Issue
Block a user