Files
2025-10-25 03:02:53 +03:00

273 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[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.1General[expr.prim.req.general]") provides a concise way to express
requirements on template arguments
that can be checked by [name lookup](basic.lookup "6.5Name lookup[basic.lookup]") or by checking properties of types and expressions[.](#general-1.sentence-1)
[requires-expression:](#nt:requires-expression "7.5.8.1General[expr.prim.req.general]")
requires [*requirement-parameter-list*](#nt:requirement-parameter-list "7.5.8.1General[expr.prim.req.general]")opt [*requirement-body*](#nt:requirement-body "7.5.8.1General[expr.prim.req.general]")
[requirement-parameter-list:](#nt:requirement-parameter-list "7.5.8.1General[expr.prim.req.general]")
( [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6Functions[dcl.fct]") )
[requirement-body:](#nt:requirement-body "7.5.8.1General[expr.prim.req.general]")
{ [*requirement-seq*](#nt:requirement-seq "7.5.8.1General[expr.prim.req.general]") }
[requirement-seq:](#nt:requirement-seq "7.5.8.1General[expr.prim.req.general]")
[*requirement*](#nt:requirement "7.5.8.1General[expr.prim.req.general]") [*requirement-seq*](#nt:requirement-seq "7.5.8.1General[expr.prim.req.general]")opt
[requirement:](#nt:requirement "7.5.8.1General[expr.prim.req.general]")
[*simple-requirement*](#nt:simple-requirement "7.5.8.2Simple requirements[expr.prim.req.simple]")
[*type-requirement*](#nt:type-requirement "7.5.8.3Type requirements[expr.prim.req.type]")
[*compound-requirement*](#nt:compound-requirement "7.5.8.4Compound requirements[expr.prim.req.compound]")
[*nested-requirement*](#nt:nested-requirement "7.5.8.5Nested 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.1General[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.1General[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.4Concept convertible_­to[concept.convertible]")<const typename T::type&>; };
A [*requires-expression*](#nt:requires-expression "7.5.8.1General[expr.prim.req.general]") can also be used in a[*requires-clause*](temp.pre#nt:requires-clause "13.1Preamble[temp.pre]") ([[temp.pre]](temp.pre "13.1Preamble")) 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.1Preamble[temp.pre]"), and the second
introduces the [*requires-expression*](#nt:requires-expression "7.5.8.1General[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.1General[expr.prim.req.general]") may introduce local parameters using a[*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6Functions[dcl.fct]")[.](#general-4.sentence-1)
A local parameter of a [*requires-expression*](#nt:requires-expression "7.5.8.1General[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.6Functions")[.](#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.1General[expr.prim.req.general]")*s*[.](#general-4.sentence-4)
The [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6Functions[dcl.fct]") of a[*requirement-parameter-list*](#nt:requirement-parameter-list "7.5.8.1General[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.1General[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.1General[expr.prim.req.general]")*s* ([[temp.deduct.general]](temp.deduct.general "13.10.3.1General")) or
the violation of the semantic constraints of those [*requirement*](#nt:requirement "7.5.8.1General[expr.prim.req.general]")*s*[.](#general-5.sentence-1)
In such cases, the [*requires-expression*](#nt:requires-expression "7.5.8.1General[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.1General[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.1General[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.1General[expr.prim.req.general]") contains invalid types or expressions in
its [*requirement*](#nt:requirement "7.5.8.1General[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.1General[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.2Simple requirements[expr.prim.req.simple]")
[*expression*](expr.comma#nt:expression "7.6.20Comma 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.2Simple requirements[expr.prim.req.simple]") asserts
the validity of an [*expression*](expr.comma#nt:expression "7.6.20Comma operator[expr.comma]")[.](#simple-1.sentence-1)
The [*expression*](expr.comma#nt:expression "7.6.20Comma 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.1General[expr.prim.req.general]") will evaluate to false if substitution of template arguments into the [*expression*](expr.comma#nt:expression "7.6.20Comma 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.1General[expr.prim.req.general]") that starts with a requires token
is never interpreted as a [*simple-requirement*](#nt:simple-requirement "7.5.8.2Simple 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.2Simple requirements[expr.prim.req.simple]") and a [*nested-requirement*](#nt:nested-requirement "7.5.8.5Nested 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.3Type requirements[expr.prim.req.type]")
typename [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]")opt [*type-name*](dcl.type.simple#nt:type-name "9.2.9.3Simple type specifiers[dcl.type.simple]") ;
typename [*splice-specifier*](basic.splice#nt:splice-specifier "6.6Splice specifiers[basic.splice]")
typename [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6Splice 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.3Type 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.3Type requirements[expr.prim.req.type]") are those of its[*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]") (if any) and[*type-name*](dcl.type.simple#nt:type-name "9.2.9.3Simple 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.1General[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.3Names of template specializations")) [*template-id*](temp.names#nt:template-id "13.3Names 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.3Type 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.1General"))[.](#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.4Compound requirements[expr.prim.req.compound]")
{ [*expression*](expr.comma#nt:expression "7.6.20Comma operator[expr.comma]") } noexceptopt [*return-type-requirement*](#nt:return-type-requirement "7.5.8.4Compound requirements[expr.prim.req.compound]")opt ;
[return-type-requirement:](#nt:return-type-requirement "7.5.8.4Compound requirements[expr.prim.req.compound]")
-> [*type-constraint*](temp.param#nt:type-constraint "13.2Template 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.4Compound requirements[expr.prim.req.compound]") asserts properties
of the [*expression*](expr.comma#nt:expression "7.6.20Comma operator[expr.comma]") E[.](#compound-1.sentence-1)
The [*expression*](expr.comma#nt:expression "7.6.20Comma 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.20Comma 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.5Exception specifications"))[.](#compound-1.2.sentence-1)
- [(1.3)](#compound-1.3)
If the [*return-type-requirement*](#nt:return-type-requirement "7.5.8.4Compound 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.4Compound 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.2Template parameters"))
of the [*type-constraint*](temp.param#nt:type-constraint "13.2Template 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.4Compound 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.2Simple 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.2Concept same_­as[concept.same]")<typename T::inner>;};
The [*compound-requirement*](#nt:compound-requirement "7.5.8.4Compound 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.2Concept 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.4Compound 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.5Nested requirements[expr.prim.req.nested]")
requires [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3Constrained 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.5Nested 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.3Constrained declarations[temp.constr.decl]") shall be satisfied ([[temp.constr.decl]](temp.constr.decl "13.5.3Constrained 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.5Nested requirements[expr.prim.req.nested]") does not result in substitution into the [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3Constrained declarations[temp.constr.decl]") other than as specified in [[temp.constr.constr]](temp.constr.constr "13.5.2Constraints")[.](#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.3Atomic constraints"))[.](#nested-1.sentence-4)
— *end example*]