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

609 lines
30 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.

[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)