273 lines
18 KiB
Markdown
273 lines
18 KiB
Markdown
[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*]
|