Files
cppdraft_translate/cppdraft/utility.md
2025-10-25 03:02:53 +03:00

466 lines
24 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.

[utility]
# 22 General utilities library [[utilities]](./#utilities)
## 22.2 Utility components [utility]
### [22.2.1](#syn) Header <utility> synopsis [[utility.syn]](utility.syn)
[1](#syn-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L29)
The header <utility> contains some basic function and class templates that are used
throughout the rest of the library[.](#syn-1.sentence-1)
// all freestanding#include <compare> // see [[compare.syn]](compare.syn "17.12.1Header <compare> synopsis")#include <initializer_list> // see [[initializer.list.syn]](initializer.list.syn "17.11.2Header <initializer_­list> synopsis")namespace std {// [[utility.swap]](#swap "22.2.2swap"), swaptemplate<class T>constexpr void swap(T& a, T& b) noexcept(*see below*); template<class T, size_t N>constexpr void swap(T (&a)[N], T (&b)[N]) noexcept(is_nothrow_swappable_v<T>); // [[utility.exchange]](#exchange "22.2.3exchange"), exchangetemplate<class T, class U = T>constexpr T exchange(T& obj, U&& new_val) noexcept(*see below*); // [[forward]](#forward "22.2.4Forward/move helpers"), forward/movetemplate<class T>constexpr T&& forward(remove_reference_t<T>& t) noexcept; template<class T>constexpr T&& forward(remove_reference_t<T>&& t) noexcept; template<class T, class U>constexpr auto forward_like(U&& x) noexcept -> *see below*; template<class T>constexpr remove_reference_t<T>&& move(T&&) noexcept; template<class T>constexpr conditional_t<!is_nothrow_move_constructible_v<T> && is_copy_constructible_v<T>, const T&, T&&> move_if_noexcept(T& x) noexcept; // [[utility.as.const]](#as.const "22.2.5Function template as_­const"), as_consttemplate<class T>constexpr add_const_t<T>& as_const(T& t) noexcept; template<class T>void as_const(const T&&) = delete; // [[declval]](#declval "22.2.6Function template declval"), declvaltemplate<class T> add_rvalue_reference_t<T> declval() noexcept; // as unevaluated operand// [[utility.intcmp]](#intcmp "22.2.7Integer comparison functions"), integer comparison functionstemplate<class T, class U>constexpr bool cmp_equal(T t, U u) noexcept; template<class T, class U>constexpr bool cmp_not_equal(T t, U u) noexcept; template<class T, class U>constexpr bool cmp_less(T t, U u) noexcept; template<class T, class U>constexpr bool cmp_greater(T t, U u) noexcept; template<class T, class U>constexpr bool cmp_less_equal(T t, U u) noexcept; template<class T, class U>constexpr bool cmp_greater_equal(T t, U u) noexcept; template<class R, class T>constexpr bool in_range(T t) noexcept; // [[utility.underlying]](#underlying "22.2.8Function template to_­underlying"), to_underlyingtemplate<class T>constexpr underlying_type_t<T> to_underlying(T value) noexcept; // [[utility.undefined]](#undefined "22.2.9Undefined behavior"), undefined behavior[[noreturn]] void unreachable(); void observable_checkpoint() noexcept; // [[intseq]](intseq "21.2Compile-time integer sequences"), compile-time integer sequencestemplate<class T, T...>struct integer_sequence; template<size_t... I>using [index_sequence](#lib:index_sequence "22.2.1Header <utility> synopsis[utility.syn]") = integer_sequence<size_t, I...>; template<class T, T N>using make_integer_sequence = integer_sequence<T, *see below*>; template<size_t N>using [make_index_sequence](#lib:make_index_sequence "22.2.1Header <utility> synopsis[utility.syn]") = make_integer_sequence<size_t, N>; template<class... T>using [index_sequence_for](#lib:index_sequence_for "22.2.1Header <utility> synopsis[utility.syn]") = make_index_sequence<sizeof...(T)>; // [[pairs]](pairs "22.3Pairs"), class template pairtemplate<class T1, class T2>struct pair; template<class T1, class T2, class U1, class U2, template<class> class TQual, template<class> class UQual>requires requires { typename pair<common_reference_t<TQual<T1>, UQual<U1>>,
common_reference_t<TQual<T2>, UQual<U2>>>; }struct basic_common_reference<pair<T1, T2>, pair<U1, U2>, TQual, UQual> {using type = pair<common_reference_t<TQual<T1>, UQual<U1>>,
common_reference_t<TQual<T2>, UQual<U2>>>; }; template<class T1, class T2, class U1, class U2>requires requires { typename pair<common_type_t<T1, U1>, common_type_t<T2, U2>>; }struct common_type<pair<T1, T2>, pair<U1, U2>> {using type = pair<common_type_t<T1, U1>, common_type_t<T2, U2>>; }; // [[pairs.spec]](pairs.spec "22.3.3Specialized algorithms"), pair specialized algorithmstemplate<class T1, class T2, class U1, class U2>constexpr bool operator==(const pair<T1, T2>&, const pair<U1, U2>&); template<class T1, class T2, class U1, class U2>constexpr common_comparison_category_t<*synth-three-way-result*<T1, U1>, *synth-three-way-result*<T2, U2>>operator<=>(const pair<T1, T2>&, const pair<U1, U2>&); template<class T1, class T2>constexpr void swap(pair<T1, T2>& x, pair<T1, T2>& y) noexcept(noexcept(x.swap(y))); template<class T1, class T2>constexpr void swap(const pair<T1, T2>& x, const pair<T1, T2>& y)noexcept(noexcept(x.swap(y))); template<class T1, class T2>constexpr *see below* make_pair(T1&&, T2&&); // [[pair.astuple]](pair.astuple "22.3.4Tuple-like access to pair"), tuple-like access to pairtemplate<class T> struct tuple_size; template<size_t I, class T> struct tuple_element; template<class T1, class T2> struct tuple_size<pair<T1, T2>>; template<size_t I, class T1, class T2> struct tuple_element<I, pair<T1, T2>>; template<size_t I, class T1, class T2>constexpr tuple_element_t<I, pair<T1, T2>>& get(pair<T1, T2>&) noexcept; template<size_t I, class T1, class T2>constexpr tuple_element_t<I, pair<T1, T2>>&& get(pair<T1, T2>&&) noexcept; template<size_t I, class T1, class T2>constexpr const tuple_element_t<I, pair<T1, T2>>& get(const pair<T1, T2>&) noexcept; template<size_t I, class T1, class T2>constexpr const tuple_element_t<I, pair<T1, T2>>&& get(const pair<T1, T2>&&) noexcept; template<class T1, class T2>constexpr T1& get(pair<T1, T2>& p) noexcept; template<class T1, class T2>constexpr const T1& get(const pair<T1, T2>& p) noexcept; template<class T1, class T2>constexpr T1&& get(pair<T1, T2>&& p) noexcept; template<class T1, class T2>constexpr const T1&& get(const pair<T1, T2>&& p) noexcept; template<class T2, class T1>constexpr T2& get(pair<T1, T2>& p) noexcept; template<class T2, class T1>constexpr const T2& get(const pair<T1, T2>& p) noexcept; template<class T2, class T1>constexpr T2&& get(pair<T1, T2>&& p) noexcept; template<class T2, class T1>constexpr const T2&& get(const pair<T1, T2>&& p) noexcept; // [[pair.piecewise]](pair.piecewise "22.3.5Piecewise construction"), pair piecewise constructionstruct piecewise_construct_t {explicit piecewise_construct_t() = default; }; inline constexpr piecewise_construct_t piecewise_construct{}; template<class... Types> class tuple; // defined in [<tuple>](tuple.syn#header:%3ctuple%3e "22.4.2Header <tuple> synopsis[tuple.syn]")// in-place constructionstruct in_place_t {explicit in_place_t() = default; }; inline constexpr in_place_t in_place{}; template<class T>struct in_place_type_t {explicit in_place_type_t() = default; }; template<class T> constexpr in_place_type_t<T> in_place_type{}; template<size_t I>struct in_place_index_t {explicit in_place_index_t() = default; }; template<size_t I> constexpr in_place_index_t<I> in_place_index{}; // nontype argument tagtemplate<auto V>struct nontype_t {explicit nontype_t() = default; }; template<auto V> constexpr nontype_t<V> nontype{}; // [[variant.monostate]](variant.monostate "22.6.8Class monostate"), class monostatestruct monostate; // [[variant.monostate.relops]](variant.monostate.relops "22.6.9monostate relational operators"), monostate relational operatorsconstexpr bool operator==(monostate, monostate) noexcept; constexpr strong_ordering operator<=>(monostate, monostate) noexcept; // [[variant.hash]](variant.hash "22.6.12Hash support"), hash supporttemplate<class T> struct hash; template<> struct hash<monostate>;}
### [22.2.2](#swap) swap [[utility.swap]](utility.swap)
[🔗](#lib:swap)
`template<class T>
constexpr void swap(T& a, T& b) noexcept(see below);
`
[1](#swap-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L251)
*Constraints*: is_move_constructible_v<T> is true andis_move_assignable_v<T> is true[.](#swap-1.sentence-1)
[2](#swap-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L256)
*Preconditions*: TypeT meets the[*Cpp17MoveConstructible*](utility.arg.requirements#:Cpp17MoveConstructible "16.4.4.2Template argument requirements[utility.arg.requirements]") (Table [31](utility.arg.requirements#tab:cpp17.moveconstructible "Table 31: Cpp17MoveConstructible requirements"))
and[*Cpp17MoveAssignable*](utility.arg.requirements#:Cpp17MoveAssignable "16.4.4.2Template argument requirements[utility.arg.requirements]") (Table [33](utility.arg.requirements#tab:cpp17.moveassignable "Table 33: Cpp17MoveAssignable requirements"))
requirements[.](#swap-2.sentence-1)
[3](#swap-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L266)
*Effects*: Exchanges values stored in two locations[.](#swap-3.sentence-1)
[4](#swap-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L270)
*Remarks*: The exception specification is equivalent to:is_nothrow_move_constructible_v<T> && is_nothrow_move_assignable_v<T>
[🔗](#lib:swap_)
`template<class T, size_t N>
constexpr void swap(T (&a)[N], T (&b)[N]) noexcept(is_nothrow_swappable_v<T>);
`
[5](#swap-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L285)
*Constraints*: is_swappable_v<T> is true[.](#swap-5.sentence-1)
[6](#swap-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L289)
*Preconditions*: a[i] is swappable with ([[swappable.requirements]](swappable.requirements "16.4.4.3Swappable requirements")) b[i] for all i in the range [0, N)[.](#swap-6.sentence-1)
[7](#swap-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L294)
*Effects*: As if by swap_ranges(a, a + N, b)[.](#swap-7.sentence-1)
### [22.2.3](#exchange) exchange [[utility.exchange]](utility.exchange)
[🔗](#lib:exchange)
`template<class T, class U = T>
constexpr T exchange(T& obj, U&& new_val) noexcept(see below);
`
[1](#exchange-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L308)
*Effects*: Equivalent to:T old_val = std::move(obj);
obj = std::forward<U>(new_val);return old_val;
[2](#exchange-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L317)
*Remarks*: The exception specification is equivalent to:is_nothrow_move_constructible_v<T> && is_nothrow_assignable_v<T&, U>
### [22.2.4](#forward) Forward/move helpers [[forward]](forward)
[1](#forward-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L328)
The library provides templated helper functions to simplify
applying move semantics to an lvalue and to simplify the implementation
of forwarding functions[.](#forward-1.sentence-1)
All functions specified in this subclause are [signal-safe](support.signal#def:evaluation,signal-safe "17.14.5Signal handlers[support.signal]")[.](#forward-1.sentence-2)
[🔗](#lib:forward)
`template<class T> constexpr T&& forward(remove_reference_t<T>& t) noexcept;
template<class T> constexpr T&& forward(remove_reference_t<T>&& t) noexcept;
`
[2](#forward-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L345)
*Mandates*: For the second overload, is_lvalue_reference_v<T> is false[.](#forward-2.sentence-1)
[3](#forward-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L349)
*Returns*: static_cast<T&&>(t)[.](#forward-3.sentence-1)
[4](#forward-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L353)
[*Example [1](#forward-example-1)*: template<class T, class A1, class A2> shared_ptr<T> factory(A1&& a1, A2&& a2) {return shared_ptr<T>(new T(std::forward<A1>(a1), std::forward<A2>(a2)));}struct A { A(int&, const double&);};
void g() { shared_ptr<A> sp1 = factory<A>(2, 1.414); // error: 2 will not bind to int&int i = 2;
shared_ptr<A> sp2 = factory<A>(i, 1.414); // OK}
In the first call to factory,A1 is deduced as int, so 2 is forwarded
to A's constructor as an rvalue[.](#forward-4.sentence-1)
In the second call to factory,A1 is deduced as int&, so i is forwarded
to A's constructor as an lvalue[.](#forward-4.sentence-2)
In
both cases, A2 is deduced as double, so
1.414 is forwarded to A's constructor as an rvalue[.](#forward-4.sentence-3)
— *end example*]
[🔗](#lib:forward_like)
`template<class T, class U>
constexpr auto forward_like(U&& x) noexcept -> see below;
`
[5](#forward-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L389)
*Mandates*: T is a referenceable type ([[defns.referenceable]](defns.referenceable "3.45referenceable type"))[.](#forward-5.sentence-1)
[6](#forward-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L393)
- [(6.1)](#forward-6.1)
Let *COPY_CONST*(A, B) be const B if A is a const type, otherwise B[.](#forward-6.1.sentence-1)
- [(6.2)](#forward-6.2)
Let *OVERRIDE_REF*(A, B) be remove_reference_t<B>&& if A is an rvalue reference type, otherwise B&[.](#forward-6.2.sentence-1)
- [(6.3)](#forward-6.3)
Let V be*OVERRIDE_REF*(T&&, *COPY_CONST*(remove_reference_t<T>, remove_reference_t<U>))
[7](#forward-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L408)
*Returns*: static_cast<V>(x)[.](#forward-7.sentence-1)
[8](#forward-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L412)
*Remarks*: The return type is V[.](#forward-8.sentence-1)
[9](#forward-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L416)
[*Example [2](#forward-example-2)*: struct accessor { vector<string>* container; decltype(auto) operator[](this auto&& self, size_t i) {return std::forward_like<decltype(self)>((*container)[i]); }};void g() { vector v{"a"s, "b"s};
accessor a{&v};
string& x = a[0]; // OK, binds to lvalue reference string&& y = std::move(a)[0]; // OK, is rvalue reference string const&& z = std::move(as_const(a))[1]; // OK, is const&& string& w = as_const(a)[1]; // error: will not bind to non-const} — *end example*]
[🔗](#lib:move,function)
`template<class T> constexpr remove_reference_t<T>&& move(T&& t) noexcept;
`
[10](#forward-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L444)
*Returns*: static_cast<remove_reference_t<T>&&>(t)[.](#forward-10.sentence-1)
[11](#forward-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L448)
[*Example [3](#forward-example-3)*: template<class T, class A1> shared_ptr<T> factory(A1&& a1) {return shared_ptr<T>(new T(std::forward<A1>(a1)));}struct A { A();
A(const A&); // copies from lvalues A(A&&); // moves from rvalues};
void g() { A a;
shared_ptr<A> sp1 = factory<A>(a); // “a'' binds to A(const A&) shared_ptr<A> sp2 = factory<A>(std::move(a)); // “a'' binds to A(A&&)}
In the first call to factory,A1 is deduced as A&, so a is forwarded
as a non-const lvalue[.](#forward-11.sentence-1)
This binds to the constructor A(const A&),
which copies the value from a[.](#forward-11.sentence-2)
In the second call to factory, because of the callstd::move(a),A1 is deduced as A, so a is forwarded
as an rvalue[.](#forward-11.sentence-3)
This binds to the constructor A(A&&),
which moves the value from a[.](#forward-11.sentence-4)
— *end example*]
[🔗](#lib:move_if_noexcept)
`template<class T> constexpr conditional_t<
!is_nothrow_move_constructible_v<T> && is_copy_constructible_v<T>, const T&, T&&>
move_if_noexcept(T& x) noexcept;
`
[12](#forward-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L488)
*Returns*: std::move(x)[.](#forward-12.sentence-1)
### [22.2.5](#as.const) Function template as_const [[utility.as.const]](utility.as.const)
[🔗](#lib:as_const)
`template<class T> constexpr add_const_t<T>& as_const(T& t) noexcept;
`
[1](#as.const-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L501)
*Returns*: t[.](#as.const-1.sentence-1)
### [22.2.6](#declval) Function template declval [[declval]](declval)
[1](#declval-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L508)
The library provides the function template declval to simplify the definition of
expressions which occur as [unevaluated operands](expr.context#def:unevaluated_operand "7.2.3Context dependence[expr.context]")[.](#declval-1.sentence-1)
[🔗](#lib:declval)
`template<class T> add_rvalue_reference_t<T> declval() noexcept; // as unevaluated operand
`
[2](#declval-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L518)
*Mandates*: This function is not odr-used ([[basic.def.odr]](basic.def.odr#term.odr.use "6.3One-definition rule"))[.](#declval-2.sentence-1)
[3](#declval-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L522)
*Remarks*: The template parameter T of declval may be an incomplete type[.](#declval-3.sentence-1)
[4](#declval-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L526)
[*Example [1](#declval-example-1)*:
template<class To, class From> decltype(static_cast<To>(declval<From>())) convert(From&&); declares a function template convert which only participates in overload resolution if the
type From can be explicitly converted to type To[.](#declval-4.sentence-1)
For another example see class
template common_type ([[meta.trans.other]](meta.trans.other "21.3.9.7Other transformations"))[.](#declval-4.sentence-2)
— *end example*]
### [22.2.7](#intcmp) Integer comparison functions [[utility.intcmp]](utility.intcmp)
[🔗](#lib:cmp_equal)
`template<class T, class U>
constexpr bool cmp_equal(T t, U u) noexcept;
`
[1](#intcmp-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L546)
*Mandates*: Both T and U are standard integer types or
extended integer types ([[basic.fundamental]](basic.fundamental "6.9.2Fundamental types"))[.](#intcmp-1.sentence-1)
[2](#intcmp-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L551)
*Effects*: Equivalent to:using UT = make_unsigned_t<T>;using UU = make_unsigned_t<U>;if constexpr (is_signed_v<T> == is_signed_v<U>)return t == u;else if constexpr (is_signed_v<T>)return t < 0 ? false : UT(t) == u;elsereturn u < 0 ? false : t == UU(u);
[🔗](#lib:cmp_not_equal)
`template<class T, class U>
constexpr bool cmp_not_equal(T t, U u) noexcept;
`
[3](#intcmp-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L573)
*Effects*: Equivalent to: return !cmp_equal(t, u);
[🔗](#lib:cmp_less)
`template<class T, class U>
constexpr bool cmp_less(T t, U u) noexcept;
`
[4](#intcmp-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L585)
*Mandates*: Both T and U are standard integer types or
extended integer types ([[basic.fundamental]](basic.fundamental "6.9.2Fundamental types"))[.](#intcmp-4.sentence-1)
[5](#intcmp-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L590)
*Effects*: Equivalent to:using UT = make_unsigned_t<T>;using UU = make_unsigned_t<U>;if constexpr (is_signed_v<T> == is_signed_v<U>)return t < u;else if constexpr (is_signed_v<T>)return t < 0 ? true : UT(t) < u;elsereturn u < 0 ? false : t < UU(u);
[🔗](#lib:cmp_greater)
`template<class T, class U>
constexpr bool cmp_greater(T t, U u) noexcept;
`
[6](#intcmp-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L612)
*Effects*: Equivalent to: return cmp_less(u, t);
[🔗](#lib:cmp_less_equal)
`template<class T, class U>
constexpr bool cmp_less_equal(T t, U u) noexcept;
`
[7](#intcmp-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L624)
*Effects*: Equivalent to: return !cmp_greater(t, u);
[🔗](#lib:cmp_greater_equal)
`template<class T, class U>
constexpr bool cmp_greater_equal(T t, U u) noexcept;
`
[8](#intcmp-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L636)
*Effects*: Equivalent to: return !cmp_less(t, u);
[🔗](#lib:in_range)
`template<class R, class T>
constexpr bool in_range(T t) noexcept;
`
[9](#intcmp-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L648)
*Mandates*: Both T and R are standard integer types or
extended integer types ([[basic.fundamental]](basic.fundamental "6.9.2Fundamental types"))[.](#intcmp-9.sentence-1)
[10](#intcmp-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L653)
*Effects*: Equivalent to:return cmp_greater_equal(t, numeric_limits<R>::min()) && cmp_less_equal(t, numeric_limits<R>::max());
[11](#intcmp-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L662)
[*Note [1](#intcmp-note-1)*:
These function templates cannot be used to comparebyte,char,char8_t,char16_t,char32_t,wchar_t, andbool[.](#intcmp-11.sentence-1)
— *end note*]
### [22.2.8](#underlying) Function template to_underlying [[utility.underlying]](utility.underlying)
[🔗](#lib:to_underlying)
`template<class T>
constexpr underlying_type_t<T> to_underlying(T value) noexcept;
`
[1](#underlying-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L683)
*Returns*: static_cast<underlying_type_t<T>>(value)[.](#underlying-1.sentence-1)
### [22.2.9](#undefined) Undefined behavior [[utility.undefined]](utility.undefined)
[🔗](#lib:unreachable)
`[[noreturn]] void unreachable();
`
[1](#undefined-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L696)
*Preconditions*: false is true[.](#undefined-1.sentence-1)
[*Note [1](#undefined-note-1)*:
This precondition cannot be satisfied, thus the behavior
of calling unreachable is undefined[.](#undefined-1.sentence-2)
— *end note*]
[2](#undefined-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L704)
[*Example [1](#undefined-example-1)*: int f(int x) {switch (x) {case 0:case 1:return x; default: std::unreachable(); }}int a = f(1); // OK, a has value 1int b = f(3); // undefined behavior — *end example*]
[🔗](#lib:observable_checkpoint)
`void observable_checkpoint() noexcept;
`
[3](#undefined-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L728)
*Effects*: Establishes an observable checkpoint ([[intro.abstract]](intro.abstract "4.1.2Abstract machine"))[.](#undefined-3.sentence-1)