This commit is contained in:
2025-10-25 03:02:53 +03:00
commit 043225d523
3416 changed files with 681196 additions and 0 deletions

608
cppdraft/concepts/lang.md Normal file
View File

@@ -0,0 +1,608 @@
[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.2Concept same_­as[concept.same]") = [is_same_v](meta.type.synop#lib:is_same_v "21.3.3Header <type_­traits> synopsis[meta.type.synop]")<T, U>; // exposition only
template<class T, class U>
concept [same_as](#concept:same_as "18.4.2Concept same_­as[concept.same]") = [same-as-impl](#concept:same-as-impl "18.4.2Concept same_­as[concept.same]")<T, U> && [same-as-impl](#concept:same-as-impl "18.4.2Concept 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.2Concept same_­as[concept.same]")<T, U> subsumes [same_as](#concept:same_as "18.4.2Concept 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.3Concept 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.3Concept 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.4Concept 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.4Concept 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.4Concept 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.17Moved-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.4Concept convertible_­to[concept.convertible]")<T, C> and[convertible_to](#concept:convertible_to "18.4.4Concept 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.5Concept common_­reference_­with[concept.commonref]") =
[same_as](#concept:same_as "18.4.2Concept same_­as[concept.same]")<common_reference_t<T, U>, common_reference_t<U, T>> &&
[convertible_to](#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<T, common_reference_t<T, U>> &&
[convertible_to](#concept:convertible_to "18.4.4Concept 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.2Equality 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.5Concept 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.5Concept common_­reference_­with[concept.commonref]") by specializing
the basic_common_reference class template ([[meta.trans.other]](meta.trans.other "21.3.9.7Other 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.6Concept common_­with[concept.common]") =
[same_as](#concept:same_as "18.4.2Concept 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.5Concept 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.5Concept 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.2Equality 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.6Concept 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.6Concept common_­with[concept.common]") by specializing thecommon_type class template ([[meta.trans.other]](meta.trans.other "21.3.9.7Other 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.7Arithmetic concepts[concepts.arithmetic]") = [is_integral_v](meta.type.synop#lib:is_integral_v "21.3.3Header <type_­traits> synopsis[meta.type.synop]")<T>;
template<class T>
concept [signed_integral](#concept:signed_integral "18.4.7Arithmetic concepts[concepts.arithmetic]") = [integral](#concept:integral "18.4.7Arithmetic concepts[concepts.arithmetic]")<T> && [is_signed_v](meta.type.synop#lib:is_signed_v "21.3.3Header <type_­traits> synopsis[meta.type.synop]")<T>;
template<class T>
concept [unsigned_integral](#concept:unsigned_integral "18.4.7Arithmetic concepts[concepts.arithmetic]") = [integral](#concept:integral "18.4.7Arithmetic concepts[concepts.arithmetic]")<T> && ![signed_integral](#concept:signed_integral "18.4.7Arithmetic concepts[concepts.arithmetic]")<T>;
template<class T>
concept [floating_point](#concept:floating_point "18.4.7Arithmetic 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.7Arithmetic concepts[concepts.arithmetic]") can be modeled even by types that are
not signed integer types ([[basic.fundamental]](basic.fundamental "6.9.2Fundamental 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.7Arithmetic concepts[concepts.arithmetic]") can be modeled even by types that are
not unsigned integer types ([[basic.fundamental]](basic.fundamental "6.9.2Fundamental 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.8Concept assignable_­from[concept.assignable]") =
is_lvalue_reference_v<LHS> &&
[common_reference_with](#concept:common_reference_with "18.4.5Concept 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.2Concept 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.8Concept 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.17Moved-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.3Requirements"));
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.5Concept 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.5Customization 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.4Compound 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.3Partial 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.4Compound 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.13Concept move_­constructible[concept.moveconstructible]")<T> and [assignable_from](#concept:assignable_from "18.4.8Concept 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.1General")),
* [(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.15constant 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.9Concept 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.9Concept swappable[concept.swappable]") =
[common_reference_with](#concept:common_reference_with "18.4.5Concept 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.9Concept swappable[concept.swappable]") and [swappable_with](#concept:swappable_with "18.4.9Concept 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.9Concept 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.9Concept 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.10Concept 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.10Concept destructible[concept.destructible]") = [is_nothrow_destructible_v](meta.type.synop#lib:is_nothrow_destructible_v "21.3.3Header <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.2Template 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.11Concept 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.11Concept constructible_­from[concept.constructible]") = [destructible](#concept:destructible "18.4.10Concept destructible[concept.destructible]")<T> && [is_constructible_v](meta.type.synop#lib:is_constructible_v "21.3.3Header <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.12Concept default_­initializable[concept.default.init]") = [constructible_from](#concept:constructible_from "18.4.11Concept 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.13Concept move_­constructible[concept.moveconstructible]") = [constructible_from](#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<T, T> && [convertible_to](#concept:convertible_to "18.4.4Concept 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.13Concept 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.17Moved-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.14Concept copy_­constructible[concept.copyconstructible]") =
[move_constructible](#concept:move_constructible "18.4.13Concept move_­constructible[concept.moveconstructible]")<T> &&
[constructible_from](#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<T, T&> && [convertible_to](#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<T&, T> &&
[constructible_from](#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<T, const T&> && [convertible_to](#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<const T&, T> &&
[constructible_from](#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<T, const T> && [convertible_to](#concept:convertible_to "18.4.4Concept 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.14Concept 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.2Equality 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)