609 lines
30 KiB
Markdown
609 lines
30 KiB
Markdown
[concepts.lang]
|
||
|
||
# 18 Concepts library [[concepts]](./#concepts)
|
||
|
||
## 18.4 Language-related concepts [concepts.lang]
|
||
|
||
### [18.4.1](#general) General [[concepts.lang.general]](concepts.lang.general)
|
||
|
||
[1](#general-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L293)
|
||
|
||
Subclause [concepts.lang] contains the definition of concepts corresponding to language
|
||
features[.](#general-1.sentence-1)
|
||
|
||
These concepts express relationships between types, type
|
||
classifications, and fundamental type properties[.](#general-1.sentence-2)
|
||
|
||
### [18.4.2](#concept.same) Concept same_as [[concept.same]](concept.same)
|
||
|
||
[ð](#concept.same-itemdecl:1)
|
||
|
||
`template<class T, class U>
|
||
concept [same-as-impl](#concept:same-as-impl "18.4.2 Concept same_as [concept.same]") = [is_same_v](meta.type.synop#lib:is_same_v "21.3.3 Header <type_traits> synopsis [meta.type.synop]")<T, U>; // exposition only
|
||
|
||
template<class T, class U>
|
||
concept [same_as](#concept:same_as "18.4.2 Concept same_as [concept.same]") = [same-as-impl](#concept:same-as-impl "18.4.2 Concept same_as [concept.same]")<T, U> && [same-as-impl](#concept:same-as-impl "18.4.2 Concept same_as [concept.same]")<U, T>;
|
||
`
|
||
|
||
[1](#concept.same-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L309)
|
||
|
||
[*Note [1](#concept.same-note-1)*:
|
||
|
||
[same_as](#concept:same_as "18.4.2 Concept same_as [concept.same]")<T, U> subsumes [same_as](#concept:same_as "18.4.2 Concept same_as [concept.same]")<U, T> and
|
||
vice versa[.](#concept.same-1.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
### [18.4.3](#concept.derived) Concept derived_from [[concept.derived]](concept.derived)
|
||
|
||
[ð](#concept:derived_from)
|
||
|
||
`template<class Derived, class Base>
|
||
concept [derived_from](#concept:derived_from "18.4.3 Concept derived_from [concept.derived]") =
|
||
is_base_of_v<Base, Derived> &&
|
||
is_convertible_v<const volatile Derived*, const volatile Base*>;
|
||
`
|
||
|
||
[1](#concept.derived-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L326)
|
||
|
||
[*Note [1](#concept.derived-note-1)*:
|
||
|
||
[derived_from](#concept:derived_from "18.4.3 Concept derived_from [concept.derived]")<Derived, Base> is satisfied if and only ifDerived is publicly and unambiguously derived from Base, orDerived and Base are the same class type ignoring cv-qualifiers[.](#concept.derived-1.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
### [18.4.4](#concept.convertible) Concept convertible_to [[concept.convertible]](concept.convertible)
|
||
|
||
[1](#concept.convertible-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L336)
|
||
|
||
Given types From and To and
|
||
an expression E whose type and value category are the same as those of declval<From>(),[convertible_to](#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<From, To> requires E to be both implicitly and explicitly convertible to type To[.](#concept.convertible-1.sentence-1)
|
||
|
||
The implicit and explicit conversions are required to produce equal
|
||
results[.](#concept.convertible-1.sentence-2)
|
||
|
||
[ð](#concept:convertible_to)
|
||
|
||
`template<class From, class To>
|
||
concept [convertible_to](#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]") =
|
||
is_convertible_v<From, To> &&
|
||
requires {
|
||
static_cast<To>(declval<From>());
|
||
};
|
||
`
|
||
|
||
[2](#concept.convertible-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L355)
|
||
|
||
Let FromR be add_rvalue_reference_t<From> andtest be the invented function:To test(FromR (&f)()) {return f();} and let f be a function with no arguments and return type FromR such that f() is equality-preserving[.](#concept.convertible-2.sentence-1)
|
||
|
||
Types From and To model [convertible_to](#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<From, To> only if:
|
||
|
||
- [(2.1)](#concept.convertible-2.1)
|
||
|
||
To is not an object or reference-to-object type, orstatic_cast<To>(f()) is equal to test(f)[.](#concept.convertible-2.1.sentence-1)
|
||
|
||
- [(2.2)](#concept.convertible-2.2)
|
||
|
||
FromR is not a reference-to-object type, or
|
||
* [(2.2.1)](#concept.convertible-2.2.1)
|
||
|
||
If FromR is an rvalue reference to a non const-qualified type, the
|
||
resulting state of the object referenced by f() after either above
|
||
expression is valid but unspecified ([[lib.types.movedfrom]](lib.types.movedfrom "16.4.6.17 Moved-from state of library types"))[.](#concept.convertible-2.2.1.sentence-1)
|
||
|
||
* [(2.2.2)](#concept.convertible-2.2.2)
|
||
|
||
Otherwise, the object referred to by f() is not modified by either above
|
||
expression[.](#concept.convertible-2.2.2.sentence-1)
|
||
|
||
### [18.4.5](#concept.commonref) Concept common_reference_with [[concept.commonref]](concept.commonref)
|
||
|
||
[1](#concept.commonref-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L390)
|
||
|
||
For two types T and U, if common_reference_t<T, U> is well-formed and denotes a type C such that both[convertible_to](#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<T, C> and[convertible_to](#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<U, C> are modeled, then T and U share a[*common reference type*](#def:common_reference_type), C[.](#concept.commonref-1.sentence-1)
|
||
|
||
[*Note [1](#concept.commonref-note-1)*:
|
||
|
||
C can be the same as T or U, or can be a
|
||
different type[.](#concept.commonref-1.sentence-2)
|
||
|
||
C can be a reference type[.](#concept.commonref-1.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#concept:common_reference_with)
|
||
|
||
`template<class T, class U>
|
||
concept [common_reference_with](#concept:common_reference_with "18.4.5 Concept common_reference_with [concept.commonref]") =
|
||
[same_as](#concept:same_as "18.4.2 Concept same_as [concept.same]")<common_reference_t<T, U>, common_reference_t<U, T>> &&
|
||
[convertible_to](#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<T, common_reference_t<T, U>> &&
|
||
[convertible_to](#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<U, common_reference_t<T, U>>;
|
||
`
|
||
|
||
[2](#concept.commonref-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L412)
|
||
|
||
Let C be common_reference_t<T, U>[.](#concept.commonref-2.sentence-1)
|
||
|
||
Let t1 and t2 be equality-preserving
|
||
expressions ([[concepts.equality]](concepts.equality "18.2 Equality preservation")) such thatdecltype((t1)) and decltype((t2)) are each T, and
|
||
let u1 and u2 be equality-preserving expressions such thatdecltype((u1)) and decltype((u2)) are each U[.](#concept.commonref-2.sentence-2)
|
||
|
||
T and U model [common_reference_with](#concept:common_reference_with "18.4.5 Concept common_reference_with [concept.commonref]")<T, U> only if
|
||
|
||
- [(2.1)](#concept.commonref-2.1)
|
||
|
||
C(t1) equals C(t2) if and only if t1 equals t2, and
|
||
|
||
- [(2.2)](#concept.commonref-2.2)
|
||
|
||
C(u1) equals C(u2) if and only if u1 equals u2[.](#concept.commonref-2.sentence-3)
|
||
|
||
[3](#concept.commonref-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L428)
|
||
|
||
[*Note [2](#concept.commonref-note-2)*:
|
||
|
||
Users can customize the behavior of [common_reference_with](#concept:common_reference_with "18.4.5 Concept common_reference_with [concept.commonref]") by specializing
|
||
the basic_common_reference class template ([[meta.trans.other]](meta.trans.other "21.3.9.7 Other transformations"))[.](#concept.commonref-3.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
### [18.4.6](#concept.common) Concept common_with [[concept.common]](concept.common)
|
||
|
||
[1](#concept.common-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L437)
|
||
|
||
If T and U can both be explicitly converted to some third type,C, then T and U share a [*common type*](#def:common_type),C[.](#concept.common-1.sentence-1)
|
||
|
||
[*Note [1](#concept.common-note-1)*:
|
||
|
||
C can be the same as T or U, or can be a
|
||
different type[.](#concept.common-1.sentence-2)
|
||
|
||
C is not necessarily unique[.](#concept.common-1.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#concept:common_with)
|
||
|
||
`template<class T, class U>
|
||
concept [common_with](#concept:common_with "18.4.6 Concept common_with [concept.common]") =
|
||
[same_as](#concept:same_as "18.4.2 Concept same_as [concept.same]")<common_type_t<T, U>, common_type_t<U, T>> &&
|
||
requires {
|
||
static_cast<common_type_t<T, U>>(declval<T>());
|
||
static_cast<common_type_t<T, U>>(declval<U>());
|
||
} &&
|
||
[common_reference_with](#concept:common_reference_with "18.4.5 Concept common_reference_with [concept.commonref]")<
|
||
add_lvalue_reference_t<const T>,
|
||
add_lvalue_reference_t<const U>> &&
|
||
[common_reference_with](#concept:common_reference_with "18.4.5 Concept common_reference_with [concept.commonref]")<
|
||
add_lvalue_reference_t<common_type_t<T, U>>,
|
||
common_reference_t<
|
||
add_lvalue_reference_t<const T>,
|
||
add_lvalue_reference_t<const U>>>;
|
||
`
|
||
|
||
[2](#concept.common-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L465)
|
||
|
||
Let C be common_type_t<T, U>[.](#concept.common-2.sentence-1)
|
||
|
||
Let t1 and t2 be
|
||
equality-preserving expressions ([[concepts.equality]](concepts.equality "18.2 Equality preservation")) such thatdecltype((t1)) and decltype((t2)) are each T, and
|
||
let u1 and u2 be equality-preserving expressions such thatdecltype((u1)) and decltype((u2)) are each U[.](#concept.common-2.sentence-2)
|
||
|
||
T and U model [common_with](#concept:common_with "18.4.6 Concept common_with [concept.common]")<T, U> only if
|
||
|
||
- [(2.1)](#concept.common-2.1)
|
||
|
||
C(t1) equals C(t2) if and only if t1 equals t2, and
|
||
|
||
- [(2.2)](#concept.common-2.2)
|
||
|
||
C(u1) equals C(u2) if and only if u1 equals u2[.](#concept.common-2.sentence-3)
|
||
|
||
[3](#concept.common-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L481)
|
||
|
||
[*Note [2](#concept.common-note-2)*:
|
||
|
||
Users can customize the behavior of [common_with](#concept:common_with "18.4.6 Concept common_with [concept.common]") by specializing thecommon_type class template ([[meta.trans.other]](meta.trans.other "21.3.9.7 Other transformations"))[.](#concept.common-3.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
### [18.4.7](#concepts.arithmetic) Arithmetic concepts [[concepts.arithmetic]](concepts.arithmetic)
|
||
|
||
[ð](#concepts.arithmetic-itemdecl:1)
|
||
|
||
`template<class T>
|
||
concept [integral](#concept:integral "18.4.7 Arithmetic concepts [concepts.arithmetic]") = [is_integral_v](meta.type.synop#lib:is_integral_v "21.3.3 Header <type_traits> synopsis [meta.type.synop]")<T>;
|
||
template<class T>
|
||
concept [signed_integral](#concept:signed_integral "18.4.7 Arithmetic concepts [concepts.arithmetic]") = [integral](#concept:integral "18.4.7 Arithmetic concepts [concepts.arithmetic]")<T> && [is_signed_v](meta.type.synop#lib:is_signed_v "21.3.3 Header <type_traits> synopsis [meta.type.synop]")<T>;
|
||
template<class T>
|
||
concept [unsigned_integral](#concept:unsigned_integral "18.4.7 Arithmetic concepts [concepts.arithmetic]") = [integral](#concept:integral "18.4.7 Arithmetic concepts [concepts.arithmetic]")<T> && <T>;
|
||
template<class T>
|
||
concept [floating_point](#concept:floating_point "18.4.7 Arithmetic concepts [concepts.arithmetic]") = is_floating_point_v<T>;
|
||
`
|
||
|
||
[1](#concepts.arithmetic-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L502)
|
||
|
||
[*Note [1](#concepts.arithmetic-note-1)*:
|
||
|
||
[signed_integral](#concept:signed_integral "18.4.7 Arithmetic concepts [concepts.arithmetic]") can be modeled even by types that are
|
||
not signed integer types ([[basic.fundamental]](basic.fundamental "6.9.2 Fundamental types")); for example, char[.](#concepts.arithmetic-1.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[2](#concepts.arithmetic-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L508)
|
||
|
||
[*Note [2](#concepts.arithmetic-note-2)*:
|
||
|
||
[unsigned_integral](#concept:unsigned_integral "18.4.7 Arithmetic concepts [concepts.arithmetic]") can be modeled even by types that are
|
||
not unsigned integer types ([[basic.fundamental]](basic.fundamental "6.9.2 Fundamental types")); for example, bool[.](#concepts.arithmetic-2.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
### [18.4.8](#concept.assignable) Concept assignable_from [[concept.assignable]](concept.assignable)
|
||
|
||
[ð](#concept:assignable_from)
|
||
|
||
`template<class LHS, class RHS>
|
||
concept [assignable_from](#concept:assignable_from "18.4.8 Concept assignable_from [concept.assignable]") =
|
||
is_lvalue_reference_v<LHS> &&
|
||
[common_reference_with](#concept:common_reference_with "18.4.5 Concept common_reference_with [concept.commonref]")<const remove_reference_t<LHS>&, const remove_reference_t<RHS>&> &&
|
||
requires(LHS lhs, RHS&& rhs) {
|
||
{ lhs = std::forward<RHS>(rhs) } -> [same_as](#concept:same_as "18.4.2 Concept same_as [concept.same]")<LHS>;
|
||
};
|
||
`
|
||
|
||
[1](#concept.assignable-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L528)
|
||
|
||
Let:
|
||
|
||
- [(1.1)](#concept.assignable-1.1)
|
||
|
||
lhs be an lvalue that refers to an object lcopy such that decltype((lhs)) is LHS,
|
||
|
||
- [(1.2)](#concept.assignable-1.2)
|
||
|
||
rhs be an expression such that decltype((rhs)) is RHS, and
|
||
|
||
- [(1.3)](#concept.assignable-1.3)
|
||
|
||
rcopy be a distinct object that is equal to rhs[.](#concept.assignable-1.sentence-1)
|
||
|
||
LHS and RHS model[assignable_from](#concept:assignable_from "18.4.8 Concept assignable_from [concept.assignable]")<LHS, RHS> only if
|
||
|
||
- [(1.4)](#concept.assignable-1.4)
|
||
|
||
addressof(lhs = rhs) == addressof(lcopy)[.](#concept.assignable-1.4.sentence-1)
|
||
|
||
- [(1.5)](#concept.assignable-1.5)
|
||
|
||
After evaluating lhs = rhs:
|
||
* [(1.5.1)](#concept.assignable-1.5.1)
|
||
|
||
lhs is equal to rcopy, unless rhs is a non-const
|
||
xvalue that refers to lcopy[.](#concept.assignable-1.5.1.sentence-1)
|
||
|
||
* [(1.5.2)](#concept.assignable-1.5.2)
|
||
|
||
If rhs is a non-const xvalue, the resulting state of the
|
||
object to which it refers is valid but unspecified ([[lib.types.movedfrom]](lib.types.movedfrom "16.4.6.17 Moved-from state of library types"))[.](#concept.assignable-1.5.2.sentence-1)
|
||
|
||
* [(1.5.3)](#concept.assignable-1.5.3)
|
||
|
||
Otherwise, if rhs is a glvalue, the object to which it refers is
|
||
not modified[.](#concept.assignable-1.5.3.sentence-1)
|
||
|
||
[2](#concept.assignable-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L555)
|
||
|
||
[*Note [1](#concept.assignable-note-1)*:
|
||
|
||
Assignment need not be a total function ([[structure.requirements]](structure.requirements "16.3.2.3 Requirements"));
|
||
in particular, if assignment to an object x can result in a modification
|
||
of some other object y, then x = y is likely not in the domain
|
||
of =[.](#concept.assignable-2.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
### [18.4.9](#concept.swappable) Concept swappable [[concept.swappable]](concept.swappable)
|
||
|
||
[1](#concept.swappable-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L566)
|
||
|
||
Let t1 and t2 be equality-preserving expressions that denote
|
||
distinct equal objects of type T, and let u1 and u2 similarly denote distinct equal objects of type U[.](#concept.swappable-1.sentence-1)
|
||
|
||
[*Note [1](#concept.swappable-note-1)*:
|
||
|
||
t1 and u1 can denote distinct objects, or the same object[.](#concept.swappable-1.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
An operation[*exchanges the values*](#def:exchanges_the_values) denoted by t1 and u1 if and only
|
||
if the operation modifies neither t2 nor u2 and:
|
||
|
||
- [(1.1)](#concept.swappable-1.1)
|
||
|
||
If T and U are the same type, the result of the operation
|
||
is that t1 equals u2 and u1 equals t2[.](#concept.swappable-1.1.sentence-1)
|
||
|
||
- [(1.2)](#concept.swappable-1.2)
|
||
|
||
If T and U are different types and [common_reference_with](#concept:common_reference_with "18.4.5 Concept common_reference_with [concept.commonref]")<decltype((t1)), decltype((u1))> is modeled,
|
||
the result of the operation is that C(t1) equals C(u2) and C(u1) equals C(t2) where C is common_reference_t<decltype((t1)), decltype((u1))>[.](#concept.swappable-1.2.sentence-1)
|
||
|
||
[2](#concept.swappable-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L590)
|
||
|
||
The name ranges::swap denotes a customization point
|
||
object ([[customization.point.object]](customization.point.object "16.3.3.3.5 Customization Point Object types"))[.](#concept.swappable-2.sentence-1)
|
||
|
||
The expressionranges::swap(E1, E2) for subexpressions E1 and E2 is expression-equivalent to an expressionS determined as follows:
|
||
|
||
- [(2.1)](#concept.swappable-2.1)
|
||
|
||
S is (void)swap(E1, E2)[192](#footnote-192 "The name swap is used here unqualified.") if E1 or E2 has class or enumeration type ([[basic.compound]](basic.compound "6.9.4 Compound types")) and that expression is valid, with
|
||
overload resolution performed in a context that includes the declarationtemplate<class T>void swap(T&, T&) = delete; and does not include a declaration of ranges::swap[.](#concept.swappable-2.1.sentence-1)
|
||
If the function selected by overload resolution does not
|
||
exchange the values denoted by E1 and E2,
|
||
the program is ill-formed, no diagnostic required[.](#concept.swappable-2.1.sentence-2)
|
||
[*Note [2](#concept.swappable-note-2)*:
|
||
This precludes calling unconstrained program-defined overloads of swap[.](#concept.swappable-2.1.sentence-3)
|
||
When the deleted overload is viable, program-defined overloads
|
||
need to be more specialized ([[temp.func.order]](temp.func.order "13.7.7.3 Partial ordering of function templates")) to be selected[.](#concept.swappable-2.1.sentence-4)
|
||
â *end note*]
|
||
|
||
- [(2.2)](#concept.swappable-2.2)
|
||
|
||
Otherwise, if E1 and E2 are lvalues of array types ([[basic.compound]](basic.compound "6.9.4 Compound types"))
|
||
with equal extent and ranges::swap(*E1, *E2) is a valid expression, S is (void)ranges::swap_ranges(E1, E2),
|
||
except that noexcept(S) is equal to noexcept(ranges::swap(*E1, *E2))[.](#concept.swappable-2.2.sentence-1)
|
||
|
||
- [(2.3)](#concept.swappable-2.3)
|
||
|
||
Otherwise, if E1 and E2 are lvalues of the
|
||
same type T that models [move_constructible](#concept:move_constructible "18.4.13 Concept move_constructible [concept.moveconstructible]")<T> and [assignable_from](#concept:assignable_from "18.4.8 Concept assignable_from [concept.assignable]")<T&, T>, S is an expression that exchanges the denoted values[.](#concept.swappable-2.3.sentence-1)
|
||
S is a constant expression if
|
||
* [(2.3.1)](#concept.swappable-2.3.1)
|
||
|
||
T is a literal type ([[basic.types.general]](basic.types.general#term.literal.type "6.9.1 General")),
|
||
|
||
* [(2.3.2)](#concept.swappable-2.3.2)
|
||
|
||
both E1 = std::move(E2) and E2 = std::move(E1) are
|
||
constant subexpressions ([[defns.const.subexpr]](defns.const.subexpr "3.15 constant subexpression")), and
|
||
|
||
* [(2.3.3)](#concept.swappable-2.3.3)
|
||
|
||
the full-expressions of the initializers in the declarationsT t1(std::move(E1));
|
||
T t2(std::move(E2)); are constant subexpressions.
|
||
|
||
noexcept(S) is equal to is_nothrow_move_constructible_v<T> && is_nothrow_move_assignable_v<T>[.](#concept.swappable-2.3.sentence-2)
|
||
|
||
- [(2.4)](#concept.swappable-2.4)
|
||
|
||
Otherwise, ranges::swap(E1, E2) is ill-formed[.](#concept.swappable-2.4.sentence-1)
|
||
[*Note [3](#concept.swappable-note-3)*:
|
||
This case can result in substitution failure when ranges::swap(E1, E2) appears in the immediate context of a template instantiation[.](#concept.swappable-2.4.sentence-2)
|
||
â *end note*]
|
||
|
||
[3](#concept.swappable-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L660)
|
||
|
||
[*Note [4](#concept.swappable-note-4)*:
|
||
|
||
Whenever ranges::swap(E1, E2) is a valid expression, it
|
||
exchanges the values denoted byE1 and E2 and has type void[.](#concept.swappable-3.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#concept:swappable)
|
||
|
||
`template<class T>
|
||
concept [swappable](#concept:swappable "18.4.9 Concept swappable [concept.swappable]") = requires(T& a, T& b) { ranges::swap(a, b); };
|
||
`
|
||
|
||
[ð](#concept:swappable_with)
|
||
|
||
`template<class T, class U>
|
||
concept [swappable_with](#concept:swappable_with "18.4.9 Concept swappable [concept.swappable]") =
|
||
[common_reference_with](#concept:common_reference_with "18.4.5 Concept common_reference_with [concept.commonref]")<T, U> &&
|
||
requires(T&& t, U&& u) {
|
||
ranges::swap(std::forward<T>(t), std::forward<T>(t));
|
||
ranges::swap(std::forward<U>(u), std::forward<U>(u));
|
||
ranges::swap(std::forward<T>(t), std::forward<U>(u));
|
||
ranges::swap(std::forward<U>(u), std::forward<T>(t));
|
||
};
|
||
`
|
||
|
||
[4](#concept.swappable-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L684)
|
||
|
||
[*Note [5](#concept.swappable-note-5)*:
|
||
|
||
The semantics of the [swappable](#concept:swappable "18.4.9 Concept swappable [concept.swappable]") and [swappable_with](#concept:swappable_with "18.4.9 Concept swappable [concept.swappable]") concepts are fully defined by the ranges::swap customization point object[.](#concept.swappable-4.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[5](#concept.swappable-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L690)
|
||
|
||
[*Example [1](#concept.swappable-example-1)*:
|
||
|
||
User code can ensure that the evaluation of swap calls
|
||
is performed in an appropriate context under the various conditions as follows:#include <cassert>#include <concepts>#include <utility>namespace ranges = std::ranges;
|
||
|
||
template<class T, std::[swappable_with](#concept:swappable_with "18.4.9 Concept swappable [concept.swappable]")<T> U>void value_swap(T&& t, U&& u) { ranges::swap(std::forward<T>(t), std::forward<U>(u));}template<std::[swappable](#concept:swappable "18.4.9 Concept swappable [concept.swappable]") T>void lv_swap(T& t1, T& t2) { ranges::swap(t1, t2);}namespace N {struct A { int m; }; struct Proxy { A* a;
|
||
Proxy(A& a) : a{&a} {}friend void swap(Proxy x, Proxy y) { ranges::swap(*x.a, *y.a); }};
|
||
Proxy proxy(A& a) { return Proxy{ a }; }}int main() {int i = 1, j = 2;
|
||
lv_swap(i, j);
|
||
assert(i == 2 && j == 1);
|
||
|
||
N::A a1 = { 5 }, a2 = { -5 };
|
||
value_swap(a1, proxy(a2));
|
||
assert(a1.m == -5 && a2.m == 5);}
|
||
|
||
â *end example*]
|
||
|
||
[192)](#footnote-192)[192)](#footnoteref-192)
|
||
|
||
The name swap is used
|
||
here unqualified[.](#footnote-192.sentence-1)
|
||
|
||
### [18.4.10](#concept.destructible) Concept destructible [[concept.destructible]](concept.destructible)
|
||
|
||
[1](#concept.destructible-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L737)
|
||
|
||
The [destructible](#concept:destructible "18.4.10 Concept destructible [concept.destructible]") concept specifies properties of all types,
|
||
instances of which can be destroyed at the end of their lifetime, or reference
|
||
types[.](#concept.destructible-1.sentence-1)
|
||
|
||
[ð](#concept:destructible)
|
||
|
||
`template<class T>
|
||
concept [destructible](#concept:destructible "18.4.10 Concept destructible [concept.destructible]") = [is_nothrow_destructible_v](meta.type.synop#lib:is_nothrow_destructible_v "21.3.3 Header <type_traits> synopsis [meta.type.synop]")<T>;
|
||
`
|
||
|
||
[2](#concept.destructible-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L748)
|
||
|
||
[*Note [1](#concept.destructible-note-1)*:
|
||
|
||
Unlike the [*Cpp17Destructible*](utility.arg.requirements#:Cpp17Destructible "16.4.4.2 Template argument requirements [utility.arg.requirements]") requirements (Table [35](utility.arg.requirements#tab:cpp17.destructible "Table 35: Cpp17Destructible requirements")), this
|
||
concept forbids destructors that are potentially throwing, even if a particular
|
||
invocation of the destructor does not actually throw[.](#concept.destructible-2.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
### [18.4.11](#concept.constructible) Concept constructible_from [[concept.constructible]](concept.constructible)
|
||
|
||
[1](#concept.constructible-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L758)
|
||
|
||
The [constructible_from](#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]") concept constrains the initialization of a
|
||
variable of a given type with a particular set of argument types[.](#concept.constructible-1.sentence-1)
|
||
|
||
[ð](#concept:constructible_from)
|
||
|
||
`template<class T, class... Args>
|
||
concept [constructible_from](#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]") = [destructible](#concept:destructible "18.4.10 Concept destructible [concept.destructible]")<T> && [is_constructible_v](meta.type.synop#lib:is_constructible_v "21.3.3 Header <type_traits> synopsis [meta.type.synop]")<T, Args...>;
|
||
`
|
||
|
||
### [18.4.12](#concept.default.init) Concept default_initializable [[concept.default.init]](concept.default.init)
|
||
|
||
[ð](#concept:default_initializable)
|
||
|
||
`template<class T>
|
||
constexpr bool is-default-initializable = see below; // exposition only
|
||
|
||
template<class T>
|
||
concept [default_initializable](#concept:default_initializable "18.4.12 Concept default_initializable [concept.default.init]") = [constructible_from](#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<T> &&
|
||
requires { T{}; } &&
|
||
is-default-initializable<T>;
|
||
`
|
||
|
||
[1](#concept.default.init-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L780)
|
||
|
||
For a type T, *is-default-initializable*<T> is true if and only if the variable definitionT t; is well-formed for some invented variable t;
|
||
otherwise it is false[.](#concept.default.init-1.sentence-1)
|
||
|
||
Access checking is performed as if in a context unrelated to T[.](#concept.default.init-1.sentence-2)
|
||
|
||
Only the validity of the immediate context of the variable initialization is considered[.](#concept.default.init-1.sentence-3)
|
||
|
||
### [18.4.13](#concept.moveconstructible) Concept move_constructible [[concept.moveconstructible]](concept.moveconstructible)
|
||
|
||
[ð](#concept:move_constructible)
|
||
|
||
`template<class T>
|
||
concept [move_constructible](#concept:move_constructible "18.4.13 Concept move_constructible [concept.moveconstructible]") = [constructible_from](#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<T, T> && [convertible_to](#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<T, T>;
|
||
`
|
||
|
||
[1](#concept.moveconstructible-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L800)
|
||
|
||
If T is an object type, then let rv be an rvalue of typeT and u2 a distinct object of type T equal torv[.](#concept.moveconstructible-1.sentence-1)
|
||
|
||
T models [move_constructible](#concept:move_constructible "18.4.13 Concept move_constructible [concept.moveconstructible]") only if
|
||
|
||
- [(1.1)](#concept.moveconstructible-1.1)
|
||
|
||
After the definition T u = rv;, u is equal to u2[.](#concept.moveconstructible-1.1.sentence-1)
|
||
|
||
- [(1.2)](#concept.moveconstructible-1.2)
|
||
|
||
T(rv) is equal to u2[.](#concept.moveconstructible-1.2.sentence-1)
|
||
|
||
- [(1.3)](#concept.moveconstructible-1.3)
|
||
|
||
If T is not const, rv's resulting state is valid
|
||
but unspecified ([[lib.types.movedfrom]](lib.types.movedfrom "16.4.6.17 Moved-from state of library types")); otherwise, it is unchanged[.](#concept.moveconstructible-1.3.sentence-1)
|
||
|
||
### [18.4.14](#concept.copyconstructible) Concept copy_constructible [[concept.copyconstructible]](concept.copyconstructible)
|
||
|
||
[ð](#concept:copy_constructible)
|
||
|
||
`template<class T>
|
||
concept [copy_constructible](#concept:copy_constructible "18.4.14 Concept copy_constructible [concept.copyconstructible]") =
|
||
[move_constructible](#concept:move_constructible "18.4.13 Concept move_constructible [concept.moveconstructible]")<T> &&
|
||
[constructible_from](#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<T, T&> && [convertible_to](#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<T&, T> &&
|
||
[constructible_from](#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<T, const T&> && [convertible_to](#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<const T&, T> &&
|
||
[constructible_from](#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<T, const T> && [convertible_to](#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<const T, T>;
|
||
`
|
||
|
||
[1](#concept.copyconstructible-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L826)
|
||
|
||
If T is an object type, then let v be an lvalue of typeT or const T or an rvalue of type const T[.](#concept.copyconstructible-1.sentence-1)
|
||
|
||
T models [copy_constructible](#concept:copy_constructible "18.4.14 Concept copy_constructible [concept.copyconstructible]") only if
|
||
|
||
- [(1.1)](#concept.copyconstructible-1.1)
|
||
|
||
After the definition T u = v;,u is equal to v ([[concepts.equality]](concepts.equality "18.2 Equality preservation")) andv is not modified[.](#concept.copyconstructible-1.1.sentence-1)
|
||
|
||
- [(1.2)](#concept.copyconstructible-1.2)
|
||
|
||
T(v) is equal to v and does not modify v[.](#concept.copyconstructible-1.2.sentence-1)
|