Difference between revisions of "cpp/concepts"
(24 intermediate revisions by 11 users not shown) | |||
Line 1: | Line 1: | ||
− | {{title|Concepts library {{mark c++20}}}} | + | {{title|Concepts library {{mark since c++20}}}} |
{{cpp/concepts/navbar}} | {{cpp/concepts/navbar}} | ||
The concepts library provides definitions of fundamental library concepts that can be used to perform compile-time validation of template arguments and perform function dispatch based on properties of types. These concepts provide a foundation for equational reasoning in programs. | The concepts library provides definitions of fundamental library concepts that can be used to perform compile-time validation of template arguments and perform function dispatch based on properties of types. These concepts provide a foundation for equational reasoning in programs. | ||
− | Most concepts in the standard library impose both syntactic and semantic requirements. It is said that a standard concept is ''satisfied'' if its | + | Most concepts in the standard library impose both syntactic and semantic requirements. It is said that a standard concept is ''satisfied'' if its syntactic requirements are met, and is ''modeled'' if it is satisfied and its semantic requirements (if any) are also met. |
− | In general, only the syntactic requirements can be checked by the compiler. If the validity or meaning of a program depends whether a | + | In general, only the syntactic requirements can be checked by the compiler. If the validity or meaning of a program depends whether a sequence of template arguments models a concept, and the concept is satisfied but not modeled, or if a semantic requirement is not met at the point of use, the program is ill-formed, [[cpp/language/ndr|no diagnostic required]]. |
+ | ===Equality preservation=== | ||
+ | An expression is ''equality-preserving'' if it results in equal outputs given equal inputs, where | ||
+ | * the inputs consist of its operands (not neccessarily making the expression semantically valid), and | ||
+ | * the outputs consist of its result and all modifications to the operands by the expression, if any | ||
+ | |||
+ | where, for convenience of wording, its "operands" refer to its largest sub-expressions that consist of an [[cpp/language/expressions#Primary expressions|id-expression]] or invocations of {{ltt|cpp/utility/move|std::move}}, {{lc|std::forward}}, and {{lc|std::declval}}. | ||
+ | |||
+ | The cv-qualification and value category of each operand is determined by assuming that each template type parameter in its type denotes a cv-unqualified complete non-array object type. | ||
+ | |||
+ | Every expression required to be equality preserving is further required to be stable, that is, two evaluations of it with the same input objects must have equal outputs without any explicit intervening modification of those input objects. | ||
+ | |||
+ | Unless noted otherwise, every expression used in a [[cpp/language/requires|{{c/core|requires}} expression]] of the {{lsd|#Standard library concepts}} is required to be equality preserving, and the evaluation of the expression may modify only its non-constant operands. Operands that are constant must not be modified. | ||
+ | |||
+ | In the standard library, the following concepts are allowed to have non equality-preserving {{c/core|requires}} expressions: | ||
+ | * {{lconcept|output_iterator}} | ||
+ | * {{lconcept|indirectly_writable}} | ||
+ | * {{lconcept|invocable}} | ||
+ | * {{lconcept|weakly_incrementable}} | ||
+ | * {{lconcept|range}} | ||
+ | |||
+ | ===Implicit expression variations=== | ||
+ | A [[cpp/language/requires|{{c/core|requires}} expression]] that uses an expression that is non-modifying for some constant lvalue operand also implicitly requires additional variations of that expression that accept a non-constant lvalue or (possibly constant) rvalue for the given operand unless such an expression variation is explicitly required with differing semantics. | ||
+ | |||
+ | These ''implicit expression variations'' must meet the same semantic requirements of the declared expression. The extent to which an implementation validates the syntax of the variations is unspecified. | ||
+ | |||
+ | {{source|1= | ||
+ | template<class T> | ||
+ | concept C = requires(T a, T b, const T c, const T d) | ||
+ | { | ||
+ | c == d; // expression #1: does not modify the operands | ||
+ | a = std::move(b); // expression #2: modifies both operands | ||
+ | a = c; // expression #3: modifies the left operand `a` | ||
+ | }; | ||
+ | |||
+ | // Expression #1 implicitly requires additional expression variations that | ||
+ | // meet the requirements for c == d (including non-modification), | ||
+ | // as if the following expressions had been declared as well: | ||
+ | |||
+ | // ------ const == const ------- ------ const == non-const --- | ||
+ | // c == b; | ||
+ | // c == std::move(d); c == std::move(b); | ||
+ | // std::move(c) == d; std::move(c) == b; | ||
+ | // std::move(c) == std::move(d); std::move(c) == std::move(b); | ||
+ | |||
+ | // -- non-const == const ------- -- non-const == non-const --- | ||
+ | // a == d; a == b; | ||
+ | // a == std::move(d); a == std::move(b); | ||
+ | // std::move(a) == d; std::move(a) == b; | ||
+ | // std::move(a) == std::move(d); std::move(a) == std::move(b); | ||
+ | |||
+ | // Expression #3 implicitly requires additional expression variations that | ||
+ | // meet the requirements for a = c | ||
+ | // (including non-modification of the second operand), | ||
+ | // as if the expressions a = b (non-constant lvalue variation) | ||
+ | // and a = std::move(c) (const rvalue variation) had been declared. | ||
+ | |||
+ | // Note: Since expression #2 already requires the non-constant rvalue variation | ||
+ | // (a == std::move(b)) explicitly, expression #3 does not implicitly require it anymore. | ||
+ | |||
+ | // The type T meets the explicitly stated syntactic requirements of | ||
+ | // concept C above, but does not meet the additional implicit requirements | ||
+ | // (i.e., T satisfies but does not model C): | ||
+ | // a program requires C<T> is ill-formed (no diagnostic required). | ||
+ | struct T | ||
+ | { | ||
+ | bool operator==(const T&) const { return true; } | ||
+ | bool operator==(T&) = delete; | ||
+ | }; | ||
+ | }} | ||
+ | |||
+ | ===Standard library concepts=== | ||
{{dsc begin}} | {{dsc begin}} | ||
− | {{dsc | + | {{dsc namespace|std}} |
− | {{dsc | + | {{dsc h2|Core language concepts}} |
− | {{dsc | + | {{dsc header|concepts}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc same_as}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc derived_from}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc convertible_to}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc common_reference_with}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc common_with}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc integral}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc signed_integral}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc unsigned_integral}} |
− | {{dsc inc | cpp/concepts/dsc floating_point}} | + | {{dsc inc|cpp/concepts/dsc floating_point}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc assignable_from}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc swappable}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc destructible}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc constructible_from}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc default_initializable}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc move_constructible}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc copy_constructible}} |
− | {{dsc h2 | Comparison concepts}} | + | {{dsc h2|Comparison concepts}} |
− | {{dsc inc | cpp/concepts/dsc boolean-testable}} | + | {{dsc header|concepts}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc boolean-testable}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc equality_comparable}} |
− | {{dsc h2 | Object concepts}} | + | {{dsc inc|cpp/concepts/dsc totally_ordered}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc header|compare}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/utility/compare/dsc three_way_comparable}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc h2|Object concepts}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc header|concepts}} |
− | {{dsc h2 | Callable concepts}} | + | {{dsc inc|cpp/concepts/dsc movable}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc copyable}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc semiregular}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc inc|cpp/concepts/dsc regular}} |
− | {{dsc inc | cpp/concepts/dsc equivalence_relation}} | + | {{dsc h2|Callable concepts}} |
− | {{dsc inc | cpp/concepts/dsc | + | {{dsc header|concepts}} |
+ | {{dsc inc|cpp/concepts/dsc invocable}} | ||
+ | {{dsc inc|cpp/concepts/dsc predicate}} | ||
+ | {{dsc inc|cpp/concepts/dsc relation}} | ||
+ | {{dsc inc|cpp/concepts/dsc equivalence_relation}} | ||
+ | {{dsc inc|cpp/concepts/dsc strict_weak_order}} | ||
{{dsc end}} | {{dsc end}} | ||
− | Additional concepts can be found in [[cpp/iterator# | + | Additional concepts can be found in [[cpp/iterator#C.2B.2B20 iterator concepts|the iterators library]], [[cpp/iterator#Algorithm concepts and utilities|the algorithms library]], and [[cpp/ranges#Range_concepts|the ranges library]]. |
+ | |||
+ | ===See also=== | ||
+ | * [[cpp/named req|Named Requirements]] | ||
− | {{langlinks|es|ja|ru|zh}} | + | {{langlinks|de|es|ja|ru|zh}} |
Latest revision as of 17:31, 7 September 2024
The concepts library provides definitions of fundamental library concepts that can be used to perform compile-time validation of template arguments and perform function dispatch based on properties of types. These concepts provide a foundation for equational reasoning in programs.
Most concepts in the standard library impose both syntactic and semantic requirements. It is said that a standard concept is satisfied if its syntactic requirements are met, and is modeled if it is satisfied and its semantic requirements (if any) are also met.
In general, only the syntactic requirements can be checked by the compiler. If the validity or meaning of a program depends whether a sequence of template arguments models a concept, and the concept is satisfied but not modeled, or if a semantic requirement is not met at the point of use, the program is ill-formed, no diagnostic required.
Contents |
[edit] Equality preservation
An expression is equality-preserving if it results in equal outputs given equal inputs, where
- the inputs consist of its operands (not neccessarily making the expression semantically valid), and
- the outputs consist of its result and all modifications to the operands by the expression, if any
where, for convenience of wording, its "operands" refer to its largest sub-expressions that consist of an id-expression or invocations of std::move, std::forward, and std::declval.
The cv-qualification and value category of each operand is determined by assuming that each template type parameter in its type denotes a cv-unqualified complete non-array object type.
Every expression required to be equality preserving is further required to be stable, that is, two evaluations of it with the same input objects must have equal outputs without any explicit intervening modification of those input objects.
Unless noted otherwise, every expression used in a requires expression of the standard library concepts is required to be equality preserving, and the evaluation of the expression may modify only its non-constant operands. Operands that are constant must not be modified.
In the standard library, the following concepts are allowed to have non equality-preserving requires expressions:
[edit] Implicit expression variations
A requires expression that uses an expression that is non-modifying for some constant lvalue operand also implicitly requires additional variations of that expression that accept a non-constant lvalue or (possibly constant) rvalue for the given operand unless such an expression variation is explicitly required with differing semantics.
These implicit expression variations must meet the same semantic requirements of the declared expression. The extent to which an implementation validates the syntax of the variations is unspecified.
template<class T> concept C = requires(T a, T b, const T c, const T d) { c == d; // expression #1: does not modify the operands a = std::move(b); // expression #2: modifies both operands a = c; // expression #3: modifies the left operand `a` }; // Expression #1 implicitly requires additional expression variations that // meet the requirements for c == d (including non-modification), // as if the following expressions had been declared as well: // ------ const == const ------- ------ const == non-const --- // c == b; // c == std::move(d); c == std::move(b); // std::move(c) == d; std::move(c) == b; // std::move(c) == std::move(d); std::move(c) == std::move(b); // -- non-const == const ------- -- non-const == non-const --- // a == d; a == b; // a == std::move(d); a == std::move(b); // std::move(a) == d; std::move(a) == b; // std::move(a) == std::move(d); std::move(a) == std::move(b); // Expression #3 implicitly requires additional expression variations that // meet the requirements for a = c // (including non-modification of the second operand), // as if the expressions a = b (non-constant lvalue variation) // and a = std::move(c) (const rvalue variation) had been declared. // Note: Since expression #2 already requires the non-constant rvalue variation // (a == std::move(b)) explicitly, expression #3 does not implicitly require it anymore. // The type T meets the explicitly stated syntactic requirements of // concept C above, but does not meet the additional implicit requirements // (i.e., T satisfies but does not model C): // a program requires C<T> is ill-formed (no diagnostic required). struct T { bool operator==(const T&) const { return true; } bool operator==(T&) = delete; };
[edit] Standard library concepts
Defined in namespace
std | |
Core language concepts | |
Defined in header
<concepts> | |
(C++20) |
specifies that a type is the same as another type (concept) |
(C++20) |
specifies that a type is derived from another type (concept) |
(C++20) |
specifies that a type is implicitly convertible to another type (concept) |
(C++20) |
specifies that two types share a common reference type (concept) |
(C++20) |
specifies that two types share a common type (concept) |
(C++20) |
specifies that a type is an integral type (concept) |
(C++20) |
specifies that a type is an integral type that is signed (concept) |
(C++20) |
specifies that a type is an integral type that is unsigned (concept) |
(C++20) |
specifies that a type is a floating-point type (concept) |
(C++20) |
specifies that a type is assignable from another type (concept) |
(C++20) |
specifies that a type can be swapped or that two types can be swapped with each other (concept) |
(C++20) |
specifies that an object of the type can be destroyed (concept) |
(C++20) |
specifies that a variable of the type can be constructed from or bound to a set of argument types (concept) |
(C++20) |
specifies that an object of a type can be default constructed (concept) |
(C++20) |
specifies that an object of a type can be move constructed (concept) |
(C++20) |
specifies that an object of a type can be copy constructed and move constructed (concept) |
Comparison concepts | |
Defined in header
<concepts> | |
(C++20) |
specifies that a type can be used in Boolean contexts (exposition-only concept*) |
specifies that operator == is an equivalence relation (concept) | |
specifies that the comparison operators on the type yield a total order (concept) | |
Defined in header
<compare> | |
specifies that operator <=> produces consistent result on given types (concept) | |
Object concepts | |
Defined in header
<concepts> | |
(C++20) |
specifies that an object of a type can be moved and swapped (concept) |
(C++20) |
specifies that an object of a type can be copied, moved, and swapped (concept) |
(C++20) |
specifies that an object of a type can be copied, moved, swapped, and default constructed (concept) |
(C++20) |
specifies that a type is regular, that is, it is both semiregular and equality_comparable (concept) |
Callable concepts | |
Defined in header
<concepts> | |
(C++20) |
specifies that a callable type can be invoked with a given set of argument types (concept) |
(C++20) |
specifies that a callable type is a Boolean predicate (concept) |
(C++20) |
specifies that a callable type is a binary relation (concept) |
(C++20) |
specifies that a relation imposes an equivalence relation (concept) |
(C++20) |
specifies that a relation imposes a strict weak ordering (concept) |
Additional concepts can be found in the iterators library, the algorithms library, and the ranges library.