22 General utilities library [utilities]
22.4.6 Calling a function with a tuple of arguments [tuple.apply]
22.7 Storage for any type [any]
22.8.5 Class template specialization bad_expected_access<void> [expected.bad.void]
22.8.7 Partial specialization of expected for void types [expected.void]
22.10.6 Class template reference_wrapper [refwrap]
This Clause describes utilities that are generally useful in C++ programs; some
of these utilities are used by other elements of the C++ standard library
. These utilities are summarized in Table Clause
66.The header
contains some basic function and class templates that are used
throughout the rest of the library
.
#include <compare>
#include <initializer_list>
namespace std {
template<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>);
template<class T, class U = T>
constexpr T exchange(T& obj, U&& new_val) noexcept(see below);
template<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;
template<class T>
constexpr add_const_t<T>& as_const(T& t) noexcept;
template<class T>
void as_const(const T&&) = delete;
template<class T>
add_rvalue_reference_t<T> declval() noexcept;
template<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;
template<class T>
constexpr underlying_type_t<T> to_underlying(T value) noexcept;
[[noreturn]] void unreachable();
void observable_checkpoint() noexcept;
template<auto X, class = decltype(X)>
struct constant_wrapper;
template<class T>
concept constexpr-param =
requires { typename constant_wrapper<T::value>; };
struct cw-operators;
template<auto X>
constexpr auto cw = constant_wrapper<X>{};
template<class T, T...>
struct integer_sequence;
template<size_t... I>
using index_sequence = 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 = make_integer_sequence<size_t, N>;
template<class... T>
using index_sequence_for = make_index_sequence<sizeof...(T)>;
template<class T> struct tuple_size;
template<size_t I, class T> struct tuple_element;
template<class T, T... Values>
struct tuple_size<integer_sequence<T, Values...>>;
template<size_t I, class T, T... Values>
struct tuple_element<I, integer_sequence<T, Values...>>;
template<size_t I, class T, T... Values>
struct tuple_element<I, const integer_sequence<T, Values...>>;
template<size_t I, class T, T... Values>
constexpr T get(integer_sequence<T, Values...>) noexcept;
template<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>>;
};
template<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&&);
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;
struct piecewise_construct_t {
explicit piecewise_construct_t() = default;
};
inline constexpr piecewise_construct_t piecewise_construct{};
template<class... Types> class tuple;
struct 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{};
struct monostate;
constexpr bool operator==(monostate, monostate) noexcept;
constexpr strong_ordering operator<=>(monostate, monostate) noexcept;
template<class T> struct hash;
template<> struct hash<monostate>;
}
template<class T>
constexpr void swap(T& a, T& b) noexcept(see below);
Constraints:
is_move_constructible_v<T> is
true and
is_move_assignable_v<T> is
true. Effects: Exchanges the values of
a and
b. Remarks: The exception specification is equivalent to:
is_nothrow_move_constructible_v<T> && is_nothrow_move_assignable_v<T>
template<class T, size_t N>
constexpr void swap(T (&a)[N], T (&b)[N]) noexcept(is_nothrow_swappable_v<T>);
Constraints:
is_swappable_v<T> is
true. Effects: As if by
swap_ranges(a, a + N, b). template<class T, class U = T>
constexpr T exchange(T& obj, U&& new_val) noexcept(see below);
Effects: Equivalent to:
T old_val = std::move(obj);
obj = std::forward<U>(new_val);
return old_val;
Remarks: The exception specification is equivalent to:
is_nothrow_move_constructible_v<T> && is_nothrow_assignable_v<T&, U>
The library provides templated helper functions to simplify
applying move semantics to an lvalue and to simplify the implementation
of forwarding functions
. template<class T> constexpr T&& forward(remove_reference_t<T>& t) noexcept;
template<class T> constexpr T&& forward(remove_reference_t<T>&& t) noexcept;
Mandates: For the second overload,
is_lvalue_reference_v<T> is
false. Returns:
static_cast<T&&>(t). [
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);
int i = 2;
shared_ptr<A> sp2 = factory<A>(i, 1.414);
}
In the first call to
factory,
A1 is deduced as
int, so
2 is forwarded
to
A's constructor as an rvalue
. In the second call to
factory,
A1 is deduced as
int&, so
i is forwarded
to
A's constructor as an lvalue
. In
both cases,
A2 is deduced as
double, so
1.414 is forwarded to
A's constructor as an rvalue
. —
end example]
template<class T, class U>
constexpr auto forward_like(U&& x) noexcept -> see below;
Let
COPY_CONST(A, B) be
const B
if
A is a const type, otherwise
B.Let
OVERRIDE_REF(A, B) be
remove_reference_t<B>&&
if
A is an rvalue reference type, otherwise
B&.Let V be
OVERRIDE_REF(T&&, COPY_CONST(remove_reference_t<T>, remove_reference_t<U>))
Returns:
static_cast<V>(x). Remarks: The return type is
V. [
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];
string&& y = std::move(a)[0];
string const&& z = std::move(as_const(a))[1];
string& w = as_const(a)[1];
}
—
end example]
template<class T> constexpr remove_reference_t<T>&& move(T&& t) noexcept;
Returns:
static_cast<remove_reference_t<T>&&>(t). [
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&);
A(A&&);
};
void g() {
A a;
shared_ptr<A> sp1 = factory<A>(a);
shared_ptr<A> sp2 = factory<A>(std::move(a));
}
In the first call to
factory,
A1 is deduced as
A&, so
a is forwarded
as a non-const lvalue
. This binds to the constructor
A(const A&),
which copies the value from
a. In the second call to
factory, because of the call
std::move(a),
A1 is deduced as
A, so
a is forwarded
as an rvalue
. This binds to the constructor
A(A&&),
which moves the value from
a. —
end example]
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;
template<class T> constexpr add_const_t<T>& as_const(T& t) noexcept;
The library provides the function template
declval to simplify the definition of
expressions which occur as
unevaluated operands.template<class T> add_rvalue_reference_t<T> declval() noexcept;
Remarks: The template parameter
T of
declval may be an incomplete type
. [
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. —
end example]
template<class T, class U>
constexpr bool cmp_equal(T t, U u) noexcept;
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;
else
return u < 0 ? false : t == UU(u);
template<class T, class U>
constexpr bool cmp_not_equal(T t, U u) noexcept;
Effects: Equivalent to: return !cmp_equal(t, u);
template<class T, class U>
constexpr bool cmp_less(T t, U u) noexcept;
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;
else
return u < 0 ? false : t < UU(u);
template<class T, class U>
constexpr bool cmp_greater(T t, U u) noexcept;
Effects: Equivalent to: return cmp_less(u, t);
template<class T, class U>
constexpr bool cmp_less_equal(T t, U u) noexcept;
Effects: Equivalent to: return !cmp_greater(t, u);
template<class T, class U>
constexpr bool cmp_greater_equal(T t, U u) noexcept;
Effects: Equivalent to: return !cmp_less(t, u);
template<class R, class T>
constexpr bool in_range(T t) noexcept;
Effects: Equivalent to:
return cmp_greater_equal(t, numeric_limits<R>::min()) &&
cmp_less_equal(t, numeric_limits<R>::max());
[
Note 1:
These function templates cannot be used to compare
byte,
char,
char8_t,
char16_t,
char32_t,
wchar_t, and
bool. —
end note]
template<class T>
constexpr underlying_type_t<T> to_underlying(T value) noexcept;
Returns:
static_cast<underlying_type_t<T>>(value). [[noreturn]] void unreachable();
Preconditions:
false is
true. [
Note 1:
This precondition cannot be satisfied, thus the behavior
of calling
unreachable is undefined
. —
end note]
[
Example 1:
int f(int x) {
switch (x) {
case 0:
case 1:
return x;
default:
std::unreachable();
}
}
int a = f(1);
int b = f(3);
—
end example]
void observable_checkpoint() noexcept;
namespace std {
struct cw-operators {
template<constexpr-param T>
friend constexpr auto operator+(T) noexcept -> constant_wrapper<(+T::value)>
{ return {}; }
template<constexpr-param T>
friend constexpr auto operator-(T) noexcept -> constant_wrapper<(-T::value)>
{ return {}; }
template<constexpr-param T>
friend constexpr auto operator~(T) noexcept -> constant_wrapper<(~T::value)>
{ return {}; }
template<constexpr-param T>
friend constexpr auto operator!(T) noexcept -> constant_wrapper<(!T::value)>
{ return {}; }
template<constexpr-param T>
friend constexpr auto operator&(T) noexcept -> constant_wrapper<(&T::value)>
{ return {}; }
template<constexpr-param T>
friend constexpr auto operator*(T) noexcept -> constant_wrapper<(*T::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator+(L, R) noexcept -> constant_wrapper<(L::value + R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator-(L, R) noexcept -> constant_wrapper<(L::value - R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator*(L, R) noexcept -> constant_wrapper<(L::value * R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator/(L, R) noexcept -> constant_wrapper<(L::value / R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator%(L, R) noexcept -> constant_wrapper<(L::value % R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator<<(L, R) noexcept -> constant_wrapper<(L::value << R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator>>(L, R) noexcept -> constant_wrapper<(L::value >> R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator&(L, R) noexcept -> constant_wrapper<(L::value & R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator|(L, R) noexcept -> constant_wrapper<(L::value | R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator^(L, R) noexcept -> constant_wrapper<(L::value ^ R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
requires (!is_constructible_v<bool, decltype(L::value)> ||
!is_constructible_v<bool, decltype(R::value)>)
friend constexpr auto operator&&(L, R) noexcept
-> constant_wrapper<(L::value && R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
requires (!is_constructible_v<bool, decltype(L::value)> ||
!is_constructible_v<bool, decltype(R::value)>)
friend constexpr auto operator||(L, R) noexcept
-> constant_wrapper<(L::value || R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator<=>(L, R) noexcept
-> constant_wrapper<(L::value <=> R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator<(L, R) noexcept -> constant_wrapper<(L::value < R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator<=(L, R) noexcept -> constant_wrapper<(L::value <= R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator==(L, R) noexcept -> constant_wrapper<(L::value == R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator!=(L, R) noexcept -> constant_wrapper<(L::value != R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator>(L, R) noexcept -> constant_wrapper<(L::value > R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator>=(L, R) noexcept -> constant_wrapper<(L::value >= R::value)>
{ return {}; }
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator,(L, R) noexcept = delete;
template<constexpr-param L, constexpr-param R>
friend constexpr auto operator->*(L, R) noexcept -> constant_wrapper<L::value->*(R::value)>
{ return {}; }
template<constexpr-param T>
constexpr auto operator++(this T) noexcept
-> constant_wrapper<(++T::value)> { return {}; }
template<constexpr-param T>
constexpr auto operator++(this T, int) noexcept
-> constant_wrapper<(T::value++)> { return {}; }
template<constexpr-param T>
constexpr auto operator--(this T) noexcept
-> constant_wrapper<(--T::value)> { return {}; }
template<constexpr-param T>
constexpr auto operator--(this T, int) noexcept
-> constant_wrapper<(T::value--)> { return {}; }
template<constexpr-param T, constexpr-param R>
constexpr auto operator+=(this T, R) noexcept
-> constant_wrapper<(T::value += R::value)> { return {}; }
template<constexpr-param T, constexpr-param R>
constexpr auto operator-=(this T, R) noexcept
-> constant_wrapper<(T::value -= R::value)> { return {}; }
template<constexpr-param T, constexpr-param R>
constexpr auto operator*=(this T, R) noexcept
-> constant_wrapper<(T::value *= R::value)> { return {}; }
template<constexpr-param T, constexpr-param R>
constexpr auto operator/=(this T, R) noexcept
-> constant_wrapper<(T::value /= R::value)> { return {}; }
template<constexpr-param T, constexpr-param R>
constexpr auto operator%=(this T, R) noexcept
-> constant_wrapper<(T::value %= R::value)> { return {}; }
template<constexpr-param T, constexpr-param R>
constexpr auto operator&=(this T, R) noexcept
-> constant_wrapper<(T::value &= R::value)> { return {}; }
template<constexpr-param T, constexpr-param R>
constexpr auto operator|=(this T, R) noexcept
-> constant_wrapper<(T::value |= R::value)> { return {}; }
template<constexpr-param T, constexpr-param R>
constexpr auto operator^=(this T, R) noexcept
-> constant_wrapper<(T::value ^= R::value)> { return {}; }
template<constexpr-param T, constexpr-param R>
constexpr auto operator<<=(this T, R) noexcept
-> constant_wrapper<(T::value <<= R::value)> { return {}; }
template<constexpr-param T, constexpr-param R>
constexpr auto operator>>=(this T, R) noexcept
-> constant_wrapper<(T::value >>= R::value)> { return {}; }
};
template<auto X, class T = decltype(X)>
struct constant_wrapper : cw-operators {
static constexpr decltype(auto) value = (X);
using type = constant_wrapper;
using value_type = decltype(X);
template<constexpr-param R>
constexpr auto operator=(R) const noexcept
-> constant_wrapper<(value = R::value)> { return {}; }
constexpr operator decltype(value)() const noexcept { return value; }
template<class... Args>
static constexpr decltype(auto) operator()(Args&&... args) noexcept(see below);
template<class... Args>
static constexpr decltype(auto) operator[](Args&&... args) noexcept(see below);
};
}
The class template
constant_wrapper aids in metaprogramming by ensuring
that the evaluation of expressions comprised entirely of
constant_wrapper
are core constant expressions (
[expr.const.core]),
regardless of the context in which they appear
. In particular, this enables use of
constant_wrapper values
that are passed as arguments to constexpr functions to be used in constant expressions
.If a specialization of
constant_wrapper is instantiated with a type
T
such that
is_same_v<T, value_type> is
false,
the program is ill-formed
. [
Note 1:
The second template parameter to
constant_wrapper is present
to aid argument-dependent lookup (
[basic.lookup.argdep])
in finding overloads for which
constant_wrapper's wrapped value is a suitable argument,
but for which the
constant_wrapper itself is not
. —
end note]
[
Example 1:
constexpr auto initial_phase(auto quantity_1, auto quantity_2) {
return quantity_1 + quantity_2;
}
constexpr auto middle_phase(auto tbd) {
return tbd;
}
void final_phase(auto gathered, auto available) {
if constexpr (gathered == available)
std::cout << "Profit!\n";
}
void impeccable_underground_planning() {
auto gathered_quantity = middle_phase(initial_phase(std::cw<42>, std::cw<13>));
static_assert(gathered_quantity == 55);
auto all_available = std::cw<55>;
final_phase(gathered_quantity, all_available);
}
void deeply_flawed_underground_planning() {
constexpr auto gathered_quantity = middle_phase(initial_phase(42, 13));
constexpr auto all_available = 55;
final_phase(gathered_quantity, all_available);
}
—
end example]
template<class... Args>
static constexpr decltype(auto) operator()(Args&&... args) noexcept(see below);
Let
call-expr be
constant_wrapper<INVOKE(value, remove_cvref_t<Args>::value...)>{}
if all types in
remove_cvref_t<Args>... satisfy
constexpr-param and
constant_wrapper<INVOKE(value, remove_cvref_t<Args>::value...)> is a valid type,
otherwise let
call-expr be
INVOKE(value, std::forward<Args>(args)...).Constraints:
call-expr is a valid expression
. Effects: Equivalent to: return call-expr;
Remarks: The exception specification is equivalent to
noexcept(call-expr). template<class... Args>
static constexpr decltype(auto) operator[](Args&&... args) noexcept(see below);
Let
subscr-expr be
constant_wrapper<value[remove_cvref_t<Args>::value...]>{}
if all types in
remove_cvref_t<Args>... satisfy
constexpr-param and
constant_wrapper<value[remove_cvref_t<Args>::value...]> is a valid type,
otherwise let
subscr-expr be
value[std::forward<Args>(args)...].Constraints:
subscr-expr is a valid expression
. Effects: Equivalent to: return subscr-expr;
Remarks: The exception specification is equivalent to
noexcept(subscr-expr). The library provides a template for heterogeneous pairs of values
. The library also provides a matching function template to simplify
their construction and several templates that provide access to
pair
objects as if they were
tuple objects (see
[tuple.helper]
and
[tuple.elem])
. namespace std {
template<class T1, class T2>
struct pair {
using first_type = T1;
using second_type = T2;
T1 first;
T2 second;
pair(const pair&) = default;
pair(pair&&) = default;
constexpr explicit(see below) pair();
constexpr explicit(see below) pair(const T1& x, const T2& y);
template<class U1 = T1, class U2 = T2>
constexpr explicit(see below) pair(U1&& x, U2&& y);
template<class U1, class U2>
constexpr explicit(see below) pair(pair<U1, U2>& p);
template<class U1, class U2>
constexpr explicit(see below) pair(const pair<U1, U2>& p);
template<class U1, class U2>
constexpr explicit(see below) pair(pair<U1, U2>&& p);
template<class U1, class U2>
constexpr explicit(see below) pair(const pair<U1, U2>&& p);
template<pair-like P>
constexpr explicit(see below) pair(P&& p);
template<class... Args1, class... Args2>
constexpr pair(piecewise_construct_t,
tuple<Args1...> first_args, tuple<Args2...> second_args);
constexpr pair& operator=(const pair& p);
constexpr const pair& operator=(const pair& p) const;
template<class U1, class U2>
constexpr pair& operator=(const pair<U1, U2>& p);
template<class U1, class U2>
constexpr const pair& operator=(const pair<U1, U2>& p) const;
constexpr pair& operator=(pair&& p) noexcept(see below);
constexpr const pair& operator=(pair&& p) const;
template<class U1, class U2>
constexpr pair& operator=(pair<U1, U2>&& p);
template<class U1, class U2>
constexpr const pair& operator=(pair<U1, U2>&& p) const;
template<pair-like P>
constexpr pair& operator=(P&& p);
template<pair-like P>
constexpr const pair& operator=(P&& p) const;
constexpr void swap(pair& p) noexcept(see below);
constexpr void swap(const pair& p) const noexcept(see below);
};
template<class T1, class T2>
pair(T1, T2) -> pair<T1, T2>;
}
Member functions of
pair do not throw exceptions unless one of
the element-wise operations specified to be called for that operation
throws an exception
.The defaulted move and copy constructor, respectively, of
pair
is a constexpr function if and only if all required element-wise
initializations for move and copy, respectively,
would be constexpr-suitable (
[dcl.constexpr])
.If
(is_trivially_destructible_v<T1> && is_trivially_destructible_v<T2>)
is
true, then the destructor of
pair is trivial
.pair<T, U> is a structural type (
[temp.param])
if
T and
U are both structural types
. Two values
p1 and
p2 of type
pair<T, U>
are template-argument-equivalent (
[temp.type]) if and only if
p1.first and
p2.first are template-argument-equivalent and
p1.second and
p2.second are template-argument-equivalent
.constexpr explicit(see below) pair();
Constraints:
- is_default_constructible_v<T1> is true and
- is_default_constructible_v<T2> is true.
Effects: Value-initializes
first and
second. Remarks: The expression inside
explicit evaluates to
true
if and only if either
T1 or
T2 is not implicitly default-constructible
. [
Note 1:
This behavior can be implemented with a trait that checks
whether a
const T1& or a
const T2&
can be initialized with
{}. —
end note]
constexpr explicit(see below) pair(const T1& x, const T2& y);
Constraints:
- is_copy_constructible_v<T1> is true and
- is_copy_constructible_v<T2> is true.
Effects: Initializes
first with
x and
second with
y. Remarks: The expression inside explicit is equivalent to:
!is_convertible_v<const T1&, T1> || !is_convertible_v<const T2&, T2>
template<class U1 = T1, class U2 = T2> constexpr explicit(see below) pair(U1&& x, U2&& y);
Constraints:
- is_constructible_v<T1, U1> is true and
- is_constructible_v<T2, U2> is true.
Effects: Initializes
first with
std::forward<U1>(x) and
second
with
std::forward<U2>(y). Remarks: The expression inside explicit is equivalent to:
!is_convertible_v<U1, T1> || !is_convertible_v<U2, T2>
This constructor is defined as deleted if
reference_constructs_from_temporary_v<first_type, U1&&>
is
true or
reference_constructs_from_temporary_v<second_type, U2&&>
is
true.template<class U1, class U2> constexpr explicit(see below) pair(pair<U1, U2>& p);
template<class U1, class U2> constexpr explicit(see below) pair(const pair<U1, U2>& p);
template<class U1, class U2> constexpr explicit(see below) pair(pair<U1, U2>&& p);
template<class U1, class U2> constexpr explicit(see below) pair(const pair<U1, U2>&& p);
template<pair-like P> constexpr explicit(see below) pair(P&& p);
Let
FWD(u) be
static_cast<decltype(u)>(u).Constraints:
- For the last overload,
remove_cvref_t<P> is not a specialization of ranges::subrange,
- is_constructible_v<T1, decltype(get<0>(FWD(p)))>
is true, and
- is_constructible_v<T2, decltype(get<1>(FWD(p)))>
is true.
Effects: Initializes
first with
get<0>(FWD(p)) and
second with
get<1>(FWD(p)). Remarks: The expression inside explicit is equivalent to:
!is_convertible_v<decltype(get<0>(FWD(p))), T1> ||
!is_convertible_v<decltype(get<1>(FWD(p))), T2>
The constructor is defined as deleted if
reference_constructs_from_temporary_v<first_type, decltype(get<0>(FWD(p)))> ||
reference_constructs_from_temporary_v<second_type, decltype(get<1>(FWD(p)))>
is
true.template<class... Args1, class... Args2>
constexpr pair(piecewise_construct_t,
tuple<Args1...> first_args, tuple<Args2...> second_args);
Mandates:
- is_constructible_v<T1, Args1...> is true and
- is_constructible_v<T2, Args2...> is true.
Effects: Initializes
first with arguments of types
Args1... obtained by forwarding the elements of
first_args
and initializes
second with arguments of types
Args2...
obtained by forwarding the elements of
second_args. (Here, forwarding
an element
x of type
U within a
tuple object means calling
std::forward<U>(x).)
This form of construction, whereby constructor
arguments for
first and
second are each provided in a separate
tuple object, is called
piecewise construction. [
Note 2:
If a data member of
pair is of reference type and
its initialization binds it to a temporary object,
the program is ill-formed (
[class.base.init])
. —
end note]
constexpr pair& operator=(const pair& p);
Effects: Assigns
p.first to
first and
p.second to
second. Remarks: This operator is defined as deleted unless
is_copy_assignable_v<T1> is
true and
is_copy_assignable_v<T2> is
true. constexpr const pair& operator=(const pair& p) const;
Constraints:
- is_copy_assignable_v<const T1> is true and
- is_copy_assignable_v<const T2> is true.
Effects: Assigns
p.first to
first and
p.second to
second. template<class U1, class U2> constexpr pair& operator=(const pair<U1, U2>& p);
Constraints:
- is_assignable_v<T1&, const U1&> is true and
- is_assignable_v<T2&, const U2&> is true.
Effects: Assigns
p.first to
first and
p.second to
second. template<class U1, class U2> constexpr const pair& operator=(const pair<U1, U2>& p) const;
Constraints:
- is_assignable_v<const T1&, const U1&> is true, and
- is_assignable_v<const T2&, const U2&> is true.
Effects: Assigns
p.first to
first and
p.second to
second. constexpr pair& operator=(pair&& p) noexcept(see below);
Constraints:
- is_move_assignable_v<T1> is true and
- is_move_assignable_v<T2> is true.
Effects: Assigns
std::forward<T1>(p.first) to
first and
std::forward<T2>(p.second) to
second. Remarks: The exception specification is equivalent to:
is_nothrow_move_assignable_v<T1> && is_nothrow_move_assignable_v<T2>
constexpr const pair& operator=(pair&& p) const;
Constraints:
- is_assignable_v<const T1&, T1> is true and
- is_assignable_v<const T2&, T2> is true.
Effects: Assigns
std::forward<T1>(p.first) to
first and
std::forward<T2>(p.second) to
second. template<class U1, class U2> constexpr pair& operator=(pair<U1, U2>&& p);
Constraints:
- is_assignable_v<T1&, U1> is true and
- is_assignable_v<T2&, U2> is true.
Effects: Assigns
std::forward<U1>(p.first) first and
std::forward<U2>(p.second) to
second. template<pair-like P> constexpr pair& operator=(P&& p);
Constraints:
- different-from<P, pair> ([range.utility.helpers])
is true,
- remove_cvref_t<P> is not a specialization of ranges::subrange,
- is_assignable_v<T1&, decltype(get<0>(std::forward<P>(p)))>
is true, and
- is_assignable_v<T2&, decltype(get<1>(std::forward<P>(p)))>
is true.
Effects: Assigns
get<0>(std::forward<P>(p)) to
first and
get<1>(std::forward<P>(p)) to
second. template<pair-like P> constexpr const pair& operator=(P&& p) const;
Constraints:
- different-from<P, pair> ([range.utility.helpers])
is true,
- remove_cvref_t<P> is not a specialization of ranges::subrange,
- is_assignable_v<const T1&, decltype(get<0>(std::forward<P>(p)))>
is true, and
- is_assignable_v<const T2&, decltype(get<1>(std::forward<P>(p)))>
is true.
Effects: Assigns
get<0>(std::forward<P>(p)) to
first and
get<1>(std::forward<P>(p)) to
second. template<class U1, class U2> constexpr const pair& operator=(pair<U1, U2>&& p) const;
Constraints:
- is_assignable_v<const T1&, U1> is true, and
- is_assignable_v<const T2&, U2> is true.
Effects: Assigns
std::forward<U1>(p.first) to
first and
std::forward<U2>(u.second) to
second. constexpr void swap(pair& p) noexcept(see below);
constexpr void swap(const pair& p) const noexcept(see below);
Mandates:
For the first overload,
is_swappable_v<T1> is
true and
is_swappable_v<T2> is
true.For the second overload,
is_swappable_v<const T1> is
true and
is_swappable_v<const T2> is
true.
Effects: Swaps
first with
p.first and
second with
p.second. Remarks: The exception specification is equivalent to:
- is_nothrow_swappable_v<T1> && is_nothrow_swappable_v<T2>
for the first overload, and
- is_nothrow_swappable_v<const T1> && is_nothrow_swappable_v<const T2>
for the second overload.
template<class T1, class T2, class U1, class U2>
constexpr bool operator==(const pair<T1, T2>& x, const pair<U1, U2>& y);
Constraints:
x.first == y.first and
x.second == y.second are
valid expressions and
each of
decltype(x.first == y.first) and
decltype(x.second == y.second) models
boolean-
testable. Returns:
x.first == y.first && x.second == y.second. 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>& x, const pair<U1, U2>& y);
Effects: Equivalent to:
if (auto c = synth-three-way(x.first, y.first); c != 0) return c;
return synth-three-way(x.second, y.second);
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)));
Constraints:
For the first overload,
is_swappable_v<T1> is
true and
is_swappable_v<T2> is
true.For the second overload,
is_swappable_v<const T1> is
true and
is_swappable_v<const T2> is
true.
Effects: Equivalent to
x.swap(y). template<class T1, class T2>
constexpr pair<unwrap_ref_decay_t<T1>, unwrap_ref_decay_t<T2>> make_pair(T1&& x, T2&& y);
Returns: pair<unwrap_ref_decay_t<T1>,
unwrap_ref_decay_t<T2>>(std::forward<T1>(x), std::forward<T2>(y))
[
Example 1:
In place of:
return pair<int, double>(5, 3.1415926);
a C++ program may contain:
return make_pair(5, 3.1415926);
—
end example]
template<class T1, class T2>
struct tuple_size<pair<T1, T2>> : integral_constant<size_t, 2> { };
template<size_t I, class T1, class T2>
struct tuple_element<I, pair<T1, T2>> {
using type = see below ;
};
Result: The type
T1 if
I is 0, otherwise the type
T2. template<size_t I, class T1, class T2>
constexpr tuple_element_t<I, pair<T1, T2>>& get(pair<T1, T2>& p) noexcept;
template<size_t I, class T1, class T2>
constexpr const tuple_element_t<I, pair<T1, T2>>& get(const pair<T1, T2>& p) noexcept;
template<size_t I, class T1, class T2>
constexpr tuple_element_t<I, pair<T1, T2>>&& get(pair<T1, T2>&& p) noexcept;
template<size_t I, class T1, class T2>
constexpr const tuple_element_t<I, pair<T1, T2>>&& get(const pair<T1, T2>&& p) noexcept;
Returns:
If
I is 0, returns a reference to
p.first.If
I is 1, returns a reference to
p.second.
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;
Mandates:
T1 and
T2 are distinct types
. Returns: A reference to
p.first. 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;
Mandates:
T1 and
T2 are distinct types
. Returns: A reference to
p.second. struct piecewise_construct_t {
explicit piecewise_construct_t() = default;
};
inline constexpr piecewise_construct_t piecewise_construct{};
The
struct piecewise_construct_t is an empty class type
used as a unique type to disambiguate constructor and function overloading
. Specifically,
pair has a constructor with
piecewise_construct_t as the
first argument, immediately followed by two
tuple arguments used
for piecewise construction of the elements of the
pair object
.Subclause
[tuple] describes the tuple library that provides a tuple type as
the class template
tuple that can be instantiated with any number
of arguments
. Each template argument specifies
the type of an element in the
tuple. Consequently, tuples are
heterogeneous, fixed-size collections of values
. A specialization of
tuple with
two arguments behaves similarly to a specialization of
pair with the same two arguments
. In addition to being available via inclusion of the
header,
ignore (
[tuple.syn]) is available when
(
[utility]) is included
.A type
T models and satisfies
the exposition-only concept
tuple-like
if
remove_cvref_t<T> is a specialization of
array,
complex,
pair,
tuple, or
ranges::subrange.namespace std {
template<class... Types>
class tuple {
public:
constexpr explicit(see below) tuple();
constexpr explicit(see below) tuple(const Types&...)
noexcept(see below);
template<class... UTypes>
constexpr explicit(see below) tuple(UTypes&&...)
noexcept(see below);
tuple(const tuple&) = default;
tuple(tuple&&) = default;
template<class... UTypes>
constexpr explicit(see below) tuple(tuple<UTypes...>&);
template<class... UTypes>
constexpr explicit(see below) tuple(const tuple<UTypes...>&);
template<class... UTypes>
constexpr explicit(see below) tuple(tuple<UTypes...>&&);
template<class... UTypes>
constexpr explicit(see below) tuple(const tuple<UTypes...>&&);
template<class U1, class U2>
constexpr explicit(see below) tuple(pair<U1, U2>&);
template<class U1, class U2>
constexpr explicit(see below) tuple(const pair<U1, U2>&);
template<class U1, class U2>
constexpr explicit(see below) tuple(pair<U1, U2>&&);
template<class U1, class U2>
constexpr explicit(see below) tuple(const pair<U1, U2>&&);
template<tuple-like UTuple>
constexpr explicit(see below) tuple(UTuple&&);
template<class Alloc>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a);
template<class Alloc>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, const Types&...);
template<class Alloc, class... UTypes>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, UTypes&&...);
template<class Alloc>
constexpr tuple(allocator_arg_t, const Alloc& a, const tuple&);
template<class Alloc>
constexpr tuple(allocator_arg_t, const Alloc& a, tuple&&);
template<class Alloc, class... UTypes>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&);
template<class Alloc, class... UTypes>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&);
template<class Alloc, class... UTypes>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&&);
template<class Alloc, class... UTypes>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&&);
template<class Alloc, class U1, class U2>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&);
template<class Alloc, class U1, class U2>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&);
template<class Alloc, class U1, class U2>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&&);
template<class Alloc, class U1, class U2>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&&);
template<class Alloc, tuple-like UTuple>
constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, UTuple&&);
constexpr tuple& operator=(const tuple&);
constexpr const tuple& operator=(const tuple&) const;
constexpr tuple& operator=(tuple&&) noexcept(see below);
constexpr const tuple& operator=(tuple&&) const;
template<class... UTypes>
constexpr tuple& operator=(const tuple<UTypes...>&);
template<class... UTypes>
constexpr const tuple& operator=(const tuple<UTypes...>&) const;
template<class... UTypes>
constexpr tuple& operator=(tuple<UTypes...>&&);
template<class... UTypes>
constexpr const tuple& operator=(tuple<UTypes...>&&) const;
template<class U1, class U2>
constexpr tuple& operator=(const pair<U1, U2>&);
template<class U1, class U2>
constexpr const tuple& operator=(const pair<U1, U2>&) const;
template<class U1, class U2>
constexpr tuple& operator=(pair<U1, U2>&&);
template<class U1, class U2>
constexpr const tuple& operator=(pair<U1, U2>&&) const;
template<tuple-like UTuple>
constexpr tuple& operator=(UTuple&&);
template<tuple-like UTuple>
constexpr const tuple& operator=(UTuple&&) const;
constexpr void swap(tuple&) noexcept(see below);
constexpr void swap(const tuple&) const noexcept(see below);
};
template<class... UTypes>
tuple(UTypes...) -> tuple<UTypes...>;
template<class T1, class T2>
tuple(pair<T1, T2>) -> tuple<T1, T2>;
template<class Alloc, class... UTypes>
tuple(allocator_arg_t, Alloc, UTypes...) -> tuple<UTypes...>;
template<class Alloc, class T1, class T2>
tuple(allocator_arg_t, Alloc, pair<T1, T2>) -> tuple<T1, T2>;
template<class Alloc, class... UTypes>
tuple(allocator_arg_t, Alloc, tuple<UTypes...>) -> tuple<UTypes...>;
}
If a program declares an explicit or partial specialization of
tuple,
the program is ill-formed, no diagnostic required
.In the descriptions that follow, let
i be in the range
[
0, sizeof...(Types)) in order,
Ti
be the
ith type in
Types, and
Ui be the
ith type in a template parameter pack named
UTypes, where indexing
is zero-based
.For each
tuple constructor, an exception is thrown only if the construction of
one of the types in
Types throws an exception
.The defaulted move and copy constructor, respectively, of
tuple is a constexpr function if and only if all
required element-wise initializations for move and copy, respectively,
would be constexpr-suitable (
[dcl.constexpr])
. The defaulted move and copy constructor of
tuple<> are
constexpr functions
.If
is_trivially_destructible_v<Ti> is
true for all
Ti,
then the destructor of
tuple is trivial
.The default constructor of
tuple<> is trivial
.constexpr explicit(see below) tuple();
Constraints:
is_default_constructible_v<Ti> is
true for all
i. Effects: Value-initializes each element
. Remarks: The expression inside
explicit evaluates to
true
if and only if
Ti is not
copy-list-initializable from an empty list
for at least one
i. [
Note 1:
This behavior can be implemented with a trait that checks whether
a
const Ti& can be initialized with
{}. —
end note]
constexpr explicit(see below) tuple(const Types&...)
noexcept((is_nothrow_copy_constructible_v<Types> && ...));
Constraints:
sizeof...(Types) ≥ 1 and
is_copy_constructible_v<Ti> is
true for all
i. Effects: Initializes each element with the value of the
corresponding parameter
. Remarks: The expression inside explicit is equivalent to:
!conjunction_v<is_convertible<const Types&, Types>...>
template<class... UTypes> constexpr explicit(see below) tuple(UTypes&&... u)
noexcept((is_nothrow_constructible_v<Types, UTypes> && ...));
Let
disambiguating-constraint be:
- negation<is_same<remove_cvref_t<U0>, tuple>>
if sizeof...(Types) is 1;
- otherwise,
bool_constant<!is_same_v<remove_cvref_t<U0>, allocator_arg_t> ||
is_-
same_v<remove_cvref_t<T0>, allocator_arg_t>>
if sizeof...(Types) is 2 or 3; - otherwise, true_type.
Constraints:
- sizeof...(Types) equals sizeof...(UTypes),
- sizeof...(Types) ≥ 1, and
- conjunction_v<disambiguating-constraint,
is_constructible<Types, UTypes>...> is
true.
Effects: Initializes the elements in the tuple with the
corresponding value in
std::forward<UTypes>(u). Remarks: The expression inside explicit is equivalent to:
!conjunction_v<is_convertible<UTypes, Types>...>
This constructor is defined as deleted if
(reference_constructs_from_temporary_v<Types, UTypes&&> || ...)
is
true.tuple(const tuple& u) = default;
Mandates:
is_copy_constructible_v<Ti> is
true for all
i. Effects: Initializes each element of
*this with the
corresponding element of
u. tuple(tuple&& u) = default;
Constraints:
is_move_constructible_v<Ti> is
true for all
i. Effects: For all
i, initializes the
ith element of
*this with
std::forward<Ti>(get<i>(u)). template<class... UTypes> constexpr explicit(see below) tuple(tuple<UTypes...>& u);
template<class... UTypes> constexpr explicit(see below) tuple(const tuple<UTypes...>& u);
template<class... UTypes> constexpr explicit(see below) tuple(tuple<UTypes...>&& u);
template<class... UTypes> constexpr explicit(see below) tuple(const tuple<UTypes...>&& u);
Let
I be the pack
0, 1, …, (sizeof...(Types) - 1). Let
FWD(u) be
static_cast<decltype(u)>(u).Constraints:
- sizeof...(Types) equals sizeof...(UTypes), and
- (is_constructible_v<Types, decltype(get<I>(FWD(u)))> && ...)
is true, and
- either sizeof...(Types) is not 1, or
(when Types... expands to T and
UTypes... expands to U)
is_convertible_v<decltype(u), T>,
is_constructible_v<T, decltype(u)>, and
is_same_v<T, U> are all false.
Effects: For all
i, initializes the
ith element of
*this
with
get<i>(FWD(u)). Remarks: The expression inside explicit is equivalent to:
!(is_convertible_v<decltype(get<I>(FWD(u))), Types> && ...)
The constructor is defined as deleted if
(reference_constructs_from_temporary_v<Types, decltype(get<I>(FWD(u)))> || ...)
is
true.template<class U1, class U2> constexpr explicit(see below) tuple(pair<U1, U2>& u);
template<class U1, class U2> constexpr explicit(see below) tuple(const pair<U1, U2>& u);
template<class U1, class U2> constexpr explicit(see below) tuple(pair<U1, U2>&& u);
template<class U1, class U2> constexpr explicit(see below) tuple(const pair<U1, U2>&& u);
Let
FWD(u) be
static_cast<decltype(u)>(u).Constraints:
- sizeof...(Types) is 2,
- is_constructible_v<T0, decltype(get<0>(FWD(u)))> is true, and
- is_constructible_v<T1, decltype(get<1>(FWD(u)))> is true.
Effects: Initializes the first element with
get<0>(FWD(u)) and
the second element with
get<1>(FWD(u)). Remarks: The expression inside explicit is equivalent to:
!is_convertible_v<decltype(get<0>(FWD(u))), T0> ||
!is_convertible_v<decltype(get<1>(FWD(u))), T1>
The constructor is defined as deleted if
reference_constructs_from_temporary_v<T0, decltype(get<0>(FWD(u)))> ||
reference_constructs_from_temporary_v<T1, decltype(get<1>(FWD(u)))>
is
true.template<tuple-like UTuple>
constexpr explicit(see below) tuple(UTuple&& u);
Let
I be the pack
0, 1, …, (sizeof...(Types) - 1).Constraints:
- different-from<UTuple, tuple> ([range.utility.helpers])
is true,
- remove_cvref_t<UTuple>
is not a specialization of ranges::subrange,
- sizeof...(Types)
equals tuple_size_v<remove_cvref_t<UTuple>>,
- (is_constructible_v<Types, decltype(get<I>(std::forward<UTuple>(u)))> && ...)
is
true, and
- either sizeof...(Types) is not 1, or
(when Types... expands to T)
is_convertible_v<UTuple, T> and
is_constructible_v<T, UTuple> are both false.
Effects: For all
i, initializes the
ith element of
*this with
get<i>(std::forward<UTuple>(u)). Remarks: The expression inside explicit is equivalent to:
!(is_convertible_v<decltype(get<I>(std::forward<UTuple>(u))), Types> && ...)
The constructor is defined as deleted if
(reference_constructs_from_temporary_v<Types, decltype(get<I>(std::forward<UTuple>(u)))>
|| ...)
is
true.template<class Alloc>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a);
template<class Alloc>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, const Types&...);
template<class Alloc, class... UTypes>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, UTypes&&...);
template<class Alloc>
constexpr tuple(allocator_arg_t, const Alloc& a, const tuple&);
template<class Alloc>
constexpr tuple(allocator_arg_t, const Alloc& a, tuple&&);
template<class Alloc, class... UTypes>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&);
template<class Alloc, class... UTypes>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&);
template<class Alloc, class... UTypes>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&&);
template<class Alloc, class... UTypes>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&&);
template<class Alloc, class U1, class U2>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&);
template<class Alloc, class U1, class U2>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&);
template<class Alloc, class U1, class U2>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&&);
template<class Alloc, class U1, class U2>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&&);
template<class Alloc, tuple-like UTuple>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, UTuple&&);
Effects: Equivalent to the preceding constructors
except that each element of non-reference type is constructed with
uses-allocator construction. For each
tuple assignment operator, an exception is thrown only if the
assignment of one of the types in
Types throws an exception
. In the function descriptions that follow, let
i be in the range [
0, sizeof...(Types))
in order,
Ti be the
ith type in
Types,
and
Ui be the
ith type in a
template parameter pack named
UTypes, where indexing is zero-based
.constexpr tuple& operator=(const tuple& u);
Effects: Assigns each element of
u to the corresponding
element of
*this. Remarks: This operator is defined as deleted unless
is_copy_assignable_v<Ti> is
true for all
i. constexpr const tuple& operator=(const tuple& u) const;
Constraints:
(is_copy_assignable_v<const Types> && ...) is
true. Effects: Assigns each element of
u to the corresponding element of
*this. constexpr tuple& operator=(tuple&& u) noexcept(see below);
Constraints:
is_move_assignable_v<Ti> is
true for all
i. Effects: For all
i, assigns
std::forward<Ti>(get<i>(u)) to
get<i>(*this). Remarks: The exception specification is equivalent to the logical
and of the
following expressions:
is_nothrow_move_assignable_v<Ti>
where
Ti is the
ith type in
Types. constexpr const tuple& operator=(tuple&& u) const;
Constraints:
(is_assignable_v<const Types&, Types> && ...) is
true. Effects: For all
i,
assigns
std::forward<Ti>(get<i>(u)) to
get<i>(*this). template<class... UTypes> constexpr tuple& operator=(const tuple<UTypes...>& u);
Constraints:
- sizeof...(Types) equals sizeof...(UTypes) and
- is_assignable_v<Ti&, const Ui&> is true for all i.
Effects: Assigns each element of
u to the corresponding element
of
*this. template<class... UTypes> constexpr const tuple& operator=(const tuple<UTypes...>& u) const;
Constraints:
- sizeof...(Types) equals sizeof...(UTypes) and
- (is_assignable_v<const Types&, const UTypes&> && ...) is true.
Effects: Assigns each element of
u to the corresponding element of
*this. template<class... UTypes> constexpr tuple& operator=(tuple<UTypes...>&& u);
Constraints:
- sizeof...(Types) equals sizeof...(UTypes) and
- is_assignable_v<Ti&, Ui> is true for all i.
Effects: For all
i, assigns
std::forward<Ui>(get<i>(u)) to
get<i>(*this). template<class... UTypes> constexpr const tuple& operator=(tuple<UTypes...>&& u) const;
Constraints:
- sizeof...(Types) equals sizeof...(UTypes) and
- (is_assignable_v<const Types&, UTypes> && ...) is true.
Effects: For all
i,
assigns
std::forward<Ui>(get<i>(u)) to
get<i>(*this). template<class U1, class U2> constexpr tuple& operator=(const pair<U1, U2>& u);
Constraints:
- sizeof...(Types) is 2 and
- is_assignable_v<T0&, const U1&> is true, and
- is_assignable_v<T1&, const U2&> is true.
Effects: Assigns
u.first to the first element of
*this
and
u.second to the second element of
*this. template<class U1, class U2> constexpr const tuple& operator=(const pair<U1, U2>& u) const;
Constraints:
- sizeof...(Types) is 2,
- is_assignable_v<const T0&, const U1&> is true, and
- is_assignable_v<const T1&, const U2&> is true.
Effects: Assigns
u.first to the first element and
u.second to the second element
. template<class U1, class U2> constexpr tuple& operator=(pair<U1, U2>&& u);
Constraints:
- sizeof...(Types) is 2 and
- is_assignable_v<T0&, U1> is true, and
- is_assignable_v<T1&, U2> is true.
Effects: Assigns std::forward<U1>(u.first) to the first
element of *this and
std::forward<U2>(u.second) to the
second element of
*this. template<class U1, class U2> constexpr const tuple& operator=(pair<U1, U2>&& u) const;
Constraints:
- sizeof...(Types) is 2,
- is_assignable_v<const T0&, U1> is true, and
- is_assignable_v<const T1&, U2> is true.
Effects: Assigns std::forward<U1>(u.first) to the first element and
std::forward<U2>(u.second) to the second element
. template<tuple-like UTuple>
constexpr tuple& operator=(UTuple&& u);
Constraints:
- different-from<UTuple, tuple> ([range.utility.helpers])
is true,
- remove_cvref_t<UTuple>
is not a specialization of ranges::subrange,
- sizeof...(Types)
equals tuple_size_v<remove_cvref_t<UTuple>>, and
- is_assignable_v<Ti&, decltype(get<i>(std::forward<UTuple>(u)))>
is true for all i.
Effects: For all
i, assigns
get<i>(std::forward<UTuple>(u))
to
get<i>(*this). template<tuple-like UTuple>
constexpr const tuple& operator=(UTuple&& u) const;
Constraints:
- different-from<UTuple, tuple> ([range.utility.helpers])
is true,
- remove_cvref_t<UTuple>
is not a specialization of ranges::subrange,
- sizeof...(Types)
equals tuple_size_v<remove_cvref_t<UTuple>>, and
- is_assignable_v<const Ti&, decltype(get<i>(std::forward<UTuple>(u)))>
is true for all i.
Effects: For all
i, assigns
get<i>(std::forward<UTuple>(u)) to
get<i>(*this). constexpr void swap(tuple& rhs) noexcept(see below);
constexpr void swap(const tuple& rhs) const noexcept(see below);
Let
i be in the range [
0, sizeof...(Types)) in order
.Mandates:
For the first overload,
(is_swappable_v<Types> && ...) is
true.For the second overload,
(is_swappable_v<const Types> && ...) is
true.
Effects: For each
i, calls
swap for
get<i>(*this) and
get<i>(rhs). Throws: Nothing unless one of the element-wise
swap calls throws an exception
. Remarks: The exception specification is equivalent to
- (is_nothrow_swappable_v<Types> && ...) for the first overload and
- (is_nothrow_swappable_v<const Types> && ...) for the second overload.
template<class... TTypes>
constexpr tuple<unwrap_ref_decay_t<TTypes>...> make_tuple(TTypes&&... t);
Returns:
tuple<unwrap_ref_decay_t<TTypes>...>(std::forward<TTypes>(t)...). [
Example 1:
int i; float j;
make_tuple(1, ref(i), cref(j));
creates a tuple of type
tuple<int, int&, const float&>. —
end example]
template<class... TTypes>
constexpr tuple<TTypes&&...> forward_as_tuple(TTypes&&... t) noexcept;
Effects: Constructs a tuple of references to the arguments in
t suitable
for forwarding as arguments to a function
. Because the result may contain references
to temporary objects, a program shall ensure that the return value of this
function does not outlive any of its arguments (e.g., the program should typically
not store the result in a named variable)
.Returns:
tuple<TTypes&&...>(std::forward<TTypes>(t)...). template<class... TTypes>
constexpr tuple<TTypes&...> tie(TTypes&... t) noexcept;
Returns:
tuple<TTypes&...>(t...). [
Example 2:
tie functions allow one to create tuples that unpack
tuples into variables
. ignore can be used for elements that
are not needed:
int i; std::string s;
tie(i, ignore, s) = make_tuple(42, 3.14, "C++");
—
end example]
template<tuple-like... Tuples>
constexpr tuple<CTypes...> tuple_cat(Tuples&&... tpls);
Let
n be
sizeof...(Tuples). For every integer
0≤i<n:
Let
Ti be the
ith type in
Tuples.Let
Ui be
remove_cvref_t<Ti>.Let
tpi be the
ith element
in the function parameter pack
tpls.Let
Si be
tuple_size_v<Ui>.Let
Eki be
tuple_element_t<k, Ui>.Let
eki be
get<k>(std::forward<Ti>(tpi)).Let
Elemsi be a pack of the types
E0i,…,ESi−1i.Let
elemsi be a pack of the expressions
e0i,…,eSi−1i.
The types in
CTypes are equal to the ordered sequence of
the expanded packs of types
Elems0...,
Elems1..., …,
Elemsn−1.... Let
celems be the ordered sequence of
the expanded packs of expressions
elems0..., …,
elemsn−1....Mandates:
(is_constructible_v<CTypes, decltype(celems)> && ...) is
true. Returns:
tuple<CTypes...>(celems...). template<class F, tuple-like Tuple>
constexpr apply_result_t<F, Tuple> apply(F&& f, Tuple&& t)
noexcept(is_nothrow_applicable_v<F, Tuple>);
Effects: Given the exposition-only function template:
namespace std {
template<class F, tuple-like Tuple, size_t... I>
constexpr decltype(auto) apply-impl(F&& f, Tuple&& t, index_sequence<I...>) {
return INVOKE(std::forward<F>(f), get<I>(std::forward<Tuple>(t))...);
}
}
Equivalent to:
return apply-impl(std::forward<F>(f), std::forward<Tuple>(t),
make_index_sequence<tuple_size_v<remove_reference_t<Tuple>>>{});
template<class T, tuple-like Tuple>
constexpr T make_from_tuple(Tuple&& t);
Mandates: If
tuple_size_v<remove_reference_t<Tuple>> is 1,
then
reference_constructs_from_temporary_v<T, decltype(get<0>(declval<Tuple>()))>
is
false. Effects: Given the exposition-only function template:
namespace std {
template<class T, tuple-like Tuple, size_t... I>
requires is_constructible_v<T, decltype(get<I>(declval<Tuple>()))...>
constexpr T make-from-tuple-impl(Tuple&& t, index_sequence<I...>) {
return T(get<I>(std::forward<Tuple>(t))...);
}
}
Equivalent to:
return make-from-tuple-impl<T>(
std::forward<Tuple>(t),
make_index_sequence<tuple_size_v<remove_reference_t<Tuple>>>{});
[
Note 1:
The type of
T must be supplied
as an explicit template parameter,
as it cannot be deduced from the argument list
. —
end note]
template<class T> struct tuple_size;
Except where specified otherwise,
all specializations of
tuple_size meet the
Cpp17UnaryTypeTrait requirements (
[meta.rqmts]) with a
base characteristic of
integral_constant<size_t, N>
for some
N.template<class... Types>
struct tuple_size<tuple<Types...>> : integral_constant<size_t, sizeof...(Types)> { };
template<size_t I, class... Types>
struct tuple_element<I, tuple<Types...>> {
using type = TI;
};
Mandates:
I < sizeof...(Types). Result:
TI is the
type of the
Ith element of
Types,
where indexing is zero-based
. template<class T> struct tuple_size<const T>;
Let
TS denote
tuple_size<T> of the cv-unqualified type
T. If the expression
TS::value is well-formed
when treated as an
unevaluated operand, then
each specialization of the template meets the
Cpp17UnaryTypeTrait requirements (
[meta.rqmts])
with a base characteristic of
integral_constant<size_t, TS::value>
Otherwise, it has no member
value.Access checking is performed as if in a context
unrelated to
TS and
T. Only the validity of the immediate context of the expression is considered
. [
Note 1:
The compilation of the expression can result in side effects
such as the instantiation of class template specializations and
function template specializations, the generation of implicitly-defined functions, and so on
. Such side effects are not in the “immediate context” and
can result in the program being ill-formed
. —
end note]
In addition to being available via inclusion of the
header,
the template is available
when any of the headers
,
,
, or
are included
.template<size_t I, class T> struct tuple_element<I, const T>;
Let
TE denote
tuple_element_t<I, T> of the cv-unqualified type
T. In addition to being available via inclusion of the
header,
the template is available
when any of the headers
,
,
, or
are included
.template<size_t I, class... Types>
constexpr tuple_element_t<I, tuple<Types...>>&
get(tuple<Types...>& t) noexcept;
template<size_t I, class... Types>
constexpr tuple_element_t<I, tuple<Types...>>&&
get(tuple<Types...>&& t) noexcept;
template<size_t I, class... Types>
constexpr const tuple_element_t<I, tuple<Types...>>&
get(const tuple<Types...>& t) noexcept;
template<size_t I, class... Types>
constexpr const tuple_element_t<I, tuple<Types...>>&& get(const tuple<Types...>&& t) noexcept;
Mandates:
I < sizeof...(Types). Returns: A reference to the
Ith element of
t, where
indexing is zero-based
. [
Note 1:
For the overload marked #1,
if a type
T in
Types is some reference type
X&,
the return type is
X&, not
X&&. However, if the element type is a non-reference type
T,
the return type is
T&&. —
end note]
[
Note 2:
For the overload marked #2,
if a type
T in
Types is some reference type
X&,
the return type is
X&, not
const X&. However, if the element type is a non-reference type
T,
the return type is
const T&. This is consistent with how constness is defined to work
for non-static data members of reference type
. —
end note]
template<class T, class... Types>
constexpr T& get(tuple<Types...>& t) noexcept;
template<class T, class... Types>
constexpr T&& get(tuple<Types...>&& t) noexcept;
template<class T, class... Types>
constexpr const T& get(const tuple<Types...>& t) noexcept;
template<class T, class... Types>
constexpr const T&& get(const tuple<Types...>&& t) noexcept;
Mandates: The type
T occurs exactly once in
Types. Returns: A reference to the element of
t corresponding to the type
T in
Types. [
Example 1:
const tuple<int, const int, double, double> t(1, 2, 3.4, 5.6);
const int& i1 = get<int>(t);
const int& i2 = get<const int>(t);
const double& d = get<double>(t);
—
end example]
[
Note 3:
The reason
get is a
non-member function is that if this functionality had been
provided as a member function, code where the type
depended on a template parameter would have required using
the
template keyword
. —
end note]
template<class... TTypes, class... UTypes>
constexpr bool operator==(const tuple<TTypes...>& t, const tuple<UTypes...>& u);
template<class... TTypes, tuple-like UTuple>
constexpr bool operator==(const tuple<TTypes...>& t, const UTuple& u);
For the first overload let
UTuple be
tuple<UTypes...>.Constraints: For all
i,
where
0 ≤ i < sizeof...(TTypes),
get<i>(t) == get<i>(u) is a valid expression and
decltype(get<i>(t) == get<i>(u)) models
boolean-testable. sizeof...(TTypes) equals
tuple_size_v<UTuple>. Returns:
true if
get<i>(t) == get<i>(u) for all
i, otherwise
false. [
Note 1:
If
sizeof...(TTypes) equals zero, returns
true. —
end note]
Remarks:
The elementary comparisons are performed in order from the
zeroth index upwards
. No comparisons or element accesses are
performed after the first equality comparison that evaluates to
false.
template<class... TTypes, class... UTypes>
constexpr common_comparison_category_t<synth-three-way-result<TTypes, UTypes>...>
operator<=>(const tuple<TTypes...>& t, const tuple<UTypes...>& u);
template<class... TTypes, tuple-like UTuple>
constexpr common_comparison_category_t<synth-three-way-result<TTypes, Elems>...>
operator<=>(const tuple<TTypes...>& t, const UTuple& u);
For the second overload,
Elems denotes the pack of types
tuple_element_t<0, UTuple>,
tuple_element_t<1, UTuple>, …,
tuple_element_t<tuple_size_v<UTuple> - 1, UTuple>.Effects: Performs a lexicographical comparison between
t and
u. If
sizeof...(TTypes) equals zero,
returns
strong_ordering::equal. Otherwise, equivalent to:
if (auto c = synth-three-way(get<0>(t), get<0>(u)); c != 0) return c;
return ttail <=> utail;
where
rtail for some
r
is a tuple containing all but the first element of
r.[
Note 2:
The above definition does not require
ttail
(or
utail) to be constructed
. It might not
even be possible, as
t and
u are not required to be copy
constructible
. Also, all comparison operator functions are short circuited;
they do not perform element accesses beyond what is needed to determine the
result of the comparison
. —
end note]
In the descriptions that follow:
Let
TTypes be a pack formed by
the sequence of
tuple_element_t<i, TTuple>
for every integer
0≤i<tuple_size_v<TTuple>.Let
UTypes be a pack formed by
the sequence of
tuple_element_t<i, UTuple>
for every integer
0≤i<tuple_size_v<UTuple>.
template<tuple-like TTuple, tuple-like UTuple,
template<class> class TQual, template<class> class UQual>
struct basic_common_reference<TTuple, UTuple, TQual, UQual> {
using type = see below;
};
Constraints:
TTuple is a specialization of
tuple or
UTuple is a specialization of
tuple. is_same_v<TTuple, decay_t<TTuple>> is
true. is_same_v<UTuple, decay_t<UTuple>> is
true. tuple_size_v<TTuple> equals
tuple_size_v<UTuple>. tuple<common_reference_t<TQual<TTypes>, UQual<UTypes>>...>
denotes a type
.
Result: The member
typedef-name type denotes the type
tuple<common_reference_t<TQual<TTypes>, UQual<UTypes>>...>. template<tuple-like TTuple, tuple-like UTuple>
struct common_type<TTuple, UTuple> {
using type = see below;
};
Constraints:
TTuple is a specialization of
tuple or
UTuple is a specialization of
tuple. is_same_v<TTuple, decay_t<TTuple>> is
true. is_same_v<UTuple, decay_t<UTuple>> is
true. tuple_size_v<TTuple> equals
tuple_size_v<UTuple>. tuple<common_type_t<TTypes, UTypes>...> denotes a type
.
tuple<common_type_t<TTypes, UTypes>...>. template<class... Types, class Alloc>
struct uses_allocator<tuple<Types...>, Alloc> : true_type { };
[
Note 1:
Specialization of this trait informs other library components that
tuple can be constructed with an allocator, even though it does not have
a nested
allocator_type. —
end note]
template<class... Types>
constexpr void swap(tuple<Types...>& x, tuple<Types...>& y) noexcept(see below);
template<class... Types>
constexpr void swap(const tuple<Types...>& x, const tuple<Types...>& y) noexcept(see below);
Constraints:
For the first overload,
(is_swappable_v<Types> && ...) is
true.For the second overload,
(is_swappable_v<const Types> && ...) is
true.
Effects: As if by
x.swap(y). Remarks: The exception specification is equivalent to:
noexcept(x.swap(y))
Subclause
[optional] describes class template
optional that represents
optional objects
. An
optional object is an
object that contains the storage for another object and manages the lifetime of
this contained object, if any
. The contained object may be initialized after
the optional object has been initialized, and may be destroyed before the
optional object has been destroyed
. The initialization state of the contained
object is tracked by the optional object
.namespace std {
template<class T>
class optional {
public:
using value_type = T;
using iterator = implementation-defined;
using const_iterator = implementation-defined;
constexpr optional() noexcept;
constexpr optional(nullopt_t) noexcept;
constexpr optional(const optional&);
constexpr optional(optional&&) noexcept(see below);
template<class... Args>
constexpr explicit optional(in_place_t, Args&&...);
template<class U, class... Args>
constexpr explicit optional(in_place_t, initializer_list<U>, Args&&...);
template<class U = remove_cv_t<T>>
constexpr explicit(see below) optional(U&&);
template<class U>
constexpr explicit(see below) optional(const optional<U>&);
template<class U>
constexpr explicit(see below) optional(optional<U>&&);
constexpr ~optional();
constexpr optional& operator=(nullopt_t) noexcept;
constexpr optional& operator=(const optional&);
constexpr optional& operator=(optional&&) noexcept(see below);
template<class U = remove_cv_t<T>> constexpr optional& operator=(U&&);
template<class U> constexpr optional& operator=(const optional<U>&);
template<class U> constexpr optional& operator=(optional<U>&&);
template<class... Args> constexpr T& emplace(Args&&...);
template<class U, class... Args> constexpr T& emplace(initializer_list<U>, Args&&...);
constexpr void swap(optional&) noexcept(see below);
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
constexpr const T* operator->() const noexcept;
constexpr T* operator->() noexcept;
constexpr const T& operator*() const & noexcept;
constexpr T& operator*() & noexcept;
constexpr T&& operator*() && noexcept;
constexpr const T&& operator*() const && noexcept;
constexpr explicit operator bool() const noexcept;
constexpr bool has_value() const noexcept;
constexpr const T& value() const &;
constexpr T& value() &;
constexpr T&& value() &&;
constexpr const T&& value() const &&;
template<class U = remove_cv_t<T>> constexpr T value_or(U&&) const &;
template<class U = remove_cv_t<T>> constexpr T value_or(U&&) &&;
template<class F> constexpr auto and_then(F&& f) &;
template<class F> constexpr auto and_then(F&& f) &&;
template<class F> constexpr auto and_then(F&& f) const &;
template<class F> constexpr auto and_then(F&& f) const &&;
template<class F> constexpr auto transform(F&& f) &;
template<class F> constexpr auto transform(F&& f) &&;
template<class F> constexpr auto transform(F&& f) const &;
template<class F> constexpr auto transform(F&& f) const &&;
template<class F> constexpr optional or_else(F&& f) &&;
template<class F> constexpr optional or_else(F&& f) const &;
constexpr void reset() noexcept;
private:
union {
remove_cv_t<T> val;
};
};
template<class T>
optional(T) -> optional<T>;
}
An optional object's contained value
is nested within (
[intro.object]) the optional object
. A type
X is a
valid contained type for
optional
if
X is an lvalue reference type or a complete non-array object type,
and
remove_cvref_t<X> is a type other than
in_place_t or
nullopt_t. If a specialization of
optional is instantiated with a type
T
that is not a valid contained type for
optional, the program is ill-formed
. If
T is an object type,
T shall meet the
Cpp17Destructible requirements (Table Clause
35)
.The exposition-only variable template
converts-from-any-cvref
is used by some constructors for
optional. template<class T, class W>
constexpr bool converts-from-any-cvref =
disjunction_v<is_constructible<T, W&>, is_convertible<W&, T>,
is_constructible<T, W>, is_convertible<W, T>,
is_constructible<T, const W&>, is_convertible<const W&, T>,
is_constructible<T, const W>, is_convertible<const W, T>>;
constexpr optional() noexcept;
constexpr optional(nullopt_t) noexcept;
Postconditions:
*this does not contain a value
. Remarks: No contained value is initialized
. For every object type
T these constructors are constexpr constructors (
[dcl.constexpr])
.constexpr optional(const optional& rhs);
Effects: If
rhs contains a value, direct-non-list-initializes
val
with
rhs.val. Postconditions:
rhs.has_value() == this->has_value(). Throws: Any exception thrown by the selected constructor of
T. Remarks: This constructor is defined as deleted unless
is_copy_constructible_v<T> is
true. If
is_trivially_copy_constructible_v<T> is
true,
this constructor is trivial
.constexpr optional(optional&& rhs) noexcept(see below);
Constraints:
is_move_constructible_v<T> is
true. Effects: If
rhs contains a value, direct-non-list-initializes
val
with
std::move(rhs.val). rhs.has_value() is unchanged
. Postconditions:
rhs.has_value() == this->has_value(). Throws: Any exception thrown by the selected constructor of
T. Remarks: The exception specification is equivalent to
is_nothrow_move_constructible_v<T>. If
is_trivially_move_constructible_v<T> is
true,
this constructor is trivial
.template<class... Args> constexpr explicit optional(in_place_t, Args&&... args);
Constraints:
is_constructible_v<T, Args...> is
true. Effects: Direct-non-list-initializes
val
with
std::forward<Args>(args).... Postconditions:
*this contains a value
. Throws: Any exception thrown by the selected constructor of
T. Remarks: If
T's constructor selected for the initialization is a constexpr constructor, this constructor is a constexpr constructor
. template<class U, class... Args>
constexpr explicit optional(in_place_t, initializer_list<U> il, Args&&... args);
Constraints:
is_constructible_v<T, initializer_list<U>&, Args...> is
true. Effects: Direct-non-list-initializes
val
with
il, std::forward<Args>(args).... Postconditions:
*this contains a value
. Throws: Any exception thrown by the selected constructor of
T. Remarks: If
T's constructor selected for the initialization is a constexpr constructor, this constructor is a constexpr constructor
. template<class U = remove_cv_t<T>> constexpr explicit(see below) optional(U&& v);
Constraints:
- is_constructible_v<T, U> is true,
- is_same_v<remove_cvref_t<U>, in_place_t> is false,
- is_same_v<remove_cvref_t<U>, optional> is false, and
- if T is cv bool,
remove_cvref_t<U> is not a specialization of optional.
Effects: Direct-non-list-initializes
val
with
std::forward<U>(v). Postconditions:
*this contains a value
. Throws: Any exception thrown by the selected constructor of
T. Remarks: If
T's selected constructor is a constexpr constructor,
this constructor is a constexpr constructor
. The expression inside explicit is equivalent to:
!is_convertible_v<U, T>
template<class U> constexpr explicit(see below) optional(const optional<U>& rhs);
Constraints:
- is_constructible_v<T, const U&> is true, and
- if T is not cv bool,
converts-from-any-cvref<T, optional<U>> is false.
Effects: If
rhs contains a value,
direct-non-list-initializes
val
with
rhs.operator*(). Postconditions:
rhs.has_value() == this->has_value(). Throws: Any exception thrown by the selected constructor of
T. Remarks: The expression inside explicit is equivalent to:
!is_convertible_v<const U&, T>
template<class U> constexpr explicit(see below) optional(optional<U>&& rhs);
Constraints:
- is_constructible_v<T, U> is true, and
- if T is not cv bool,
converts-from-any-cvref<T, optional<U>> is false.
Effects: If
rhs contains a value,
direct-non-list-initializes
val
with
std::move(rhs).operator*(). rhs.has_value() is unchanged
. Postconditions:
rhs.has_value() == this->has_value(). Throws: Any exception thrown by the selected constructor of
T. Remarks: The expression inside explicit is equivalent to:
!is_convertible_v<U, T>
Effects: If
is_trivially_destructible_v<T> is
false
and
*this contains a value,
calls
val.T::~T(). Remarks: If
is_trivially_destructible_v<T> is
true, then this destructor is trivial
. constexpr optional<T>& operator=(nullopt_t) noexcept;
Effects: If
*this contains a value, calls
val.T::~T() to destroy the contained value; otherwise no effect
. Postconditions:
*this does not contain a value
. constexpr optional<T>& operator=(const optional& rhs);
Effects: See Table Clause
67. Table
67 —
optional::operator=(const optional&) effects
[tab:optional.assign.copy] | | | *this does not contain a value |
| | | direct-non-list-initializes val with rhs.val |
rhs does not contain a value | | destroys the contained value by calling val.T::~T() | |
Postconditions:
rhs.has_value() == this->has_value(). Remarks: If any exception is thrown, the result of the expression
this->has_value() remains unchanged
. If an exception is thrown during the call to
T's copy constructor, no effect
. If an exception is thrown during the call to
T's copy assignment,
the state of its contained value is as defined by the exception safety guarantee of
T's copy assignment
. This operator is defined as deleted unless
is_copy_constructible_v<T> is
true and
is_copy_assignable_v<T> is
true. If
is_trivially_copy_constructible_v<T> &&
is_trivially_copy_assignable_v<T> &&
is_trivially_destructible_v<T> is
true,
this assignment operator is trivial
.constexpr optional& operator=(optional&& rhs) noexcept(see below);
Constraints:
is_move_constructible_v<T> is
true and
is_move_assignable_v<T> is
true. Effects: See Table Clause
68. The result of the expression
rhs.has_value() remains unchanged
.Table
68 —
optional::operator=(optional&&) effects
[tab:optional.assign.move] | | | *this does not contain a value |
| | assigns std::move(rhs.val) to val | direct-non-list-initializes val with std::move(rhs.val) |
rhs does not contain a value | | destroys the contained value by calling val.T::~T() | |
Postconditions:
rhs.has_value() == this->has_value(). Remarks: The exception specification is equivalent to:
is_nothrow_move_assignable_v<T> && is_nothrow_move_constructible_v<T>
If any exception is thrown, the result of the expression
this->has_value() remains unchanged
. If an exception is thrown during the call to
T's move constructor,
the state of
rhs.val is determined by the exception safety guarantee of
T's move constructor
. If an exception is thrown during the call to
T's move assignment,
the states of
val and
rhs.val are determined by the exception safety guarantee of
T's move assignment
. If
is_trivially_move_constructible_v<T> &&
is_trivially_move_assignable_v<T> &&
is_trivially_destructible_v<T> is
true,
this assignment operator is trivial
.template<class U = remove_cv_t<T>> constexpr optional& operator=(U&& v);
Constraints:
- is_same_v<remove_cvref_t<U>, optional> is false,
- conjunction_v<is_scalar<T>, is_same<T, decay_t<U>>> is false,
- is_constructible_v<T, U> is true, and
- is_assignable_v<T&, U> is true.
Effects: If
*this contains a value,
assigns
std::forward<U>(v) to
val;
otherwise direct-non-list-initializes
val
with
std::forward<U>(v). Postconditions:
*this contains a value
. Remarks: If any exception is thrown, the result of the expression
this->has_value() remains unchanged
. If an exception is thrown during the call to
T's constructor, the state of
v is determined by the exception safety guarantee of
T's constructor
. If an exception is thrown during the call to
T's assignment,
the states of
val and
v are
determined by the exception safety guarantee of
T's assignment
.template<class U> constexpr optional<T>& operator=(const optional<U>& rhs);
Constraints:
- is_constructible_v<T, const U&> is true,
- is_assignable_v<T&, const U&> is true,
- converts-from-any-cvref<T, optional<U>> is false,
- is_assignable_v<T&, optional<U>&> is false,
- is_assignable_v<T&, optional<U>&&> is false,
- is_assignable_v<T&, const optional<U>&> is false, and
- is_assignable_v<T&, const optional<U>&&> is false.
Effects: See Table Clause
69. Table
69 —
optional::operator=(const optional<U>&) effects
[tab:optional.assign.copy.templ] | | | *this does not contain a value |
| | assigns rhs.operator*() to val | direct-non-list-initializes val with rhs.operator*() |
rhs does not contain a value | | destroys the contained value by calling val.T::~T() | |
Postconditions:
rhs.has_value() == this->has_value(). Remarks: If any exception is thrown,
the result of the expression
this->has_value() remains unchanged
. If an exception is thrown during the call to
T's constructor,
the state of
rhs.val is determined by
the exception safety guarantee of
T's constructor
. If an exception is thrown during the call to
T's assignment,
the states of
val and
rhs.val are determined by
the exception safety guarantee of
T's assignment
.template<class U> constexpr optional<T>& operator=(optional<U>&& rhs);
Constraints:
- is_constructible_v<T, U> is true,
- is_assignable_v<T&, U> is true,
- converts-from-any-cvref<T, optional<U>> is false,
- is_assignable_v<T&, optional<U>&> is false,
- is_assignable_v<T&, optional<U>&&> is false,
- is_assignable_v<T&, const optional<U>&> is false, and
- is_assignable_v<T&, const optional<U>&&> is false.
Effects: See Table Clause
70. The result of the expression
rhs.has_value() remains unchanged
.Table
70 —
optional::operator=(optional<U>&&) effects
[tab:optional.assign.move.templ] | | | *this does not contain a value |
| | assigns std::move(rhs).operator*() to val | direct-non-list-initializes val with std::move(rhs).operator*() |
rhs does not contain a value | | destroys the contained value by calling val.T::~T() | |
Postconditions:
rhs.has_value() == this->has_value(). Remarks: If any exception is thrown,
the result of the expression
this->has_value() remains unchanged
. If an exception is thrown during the call to
T's constructor,
the state of
rhs.val is determined by
the exception safety guarantee of
T's constructor
. If an exception is thrown during the call to
T's assignment,
the states of
val and
rhs.val are determined by
the exception safety guarantee of
T's assignment
.template<class... Args> constexpr T& emplace(Args&&... args);
Constraints:
is_constructible_v<T, Args...> is
true. Effects: Calls
*this = nullopt. Then direct-non-list-initializes
val
with
std::forward<Args>(args)....Postconditions:
*this contains a value
. Throws: Any exception thrown by the selected constructor of
T. Remarks: If an exception is thrown during the call to
T's constructor,
*this does not contain a value, and
the previous
val (if any) has been destroyed
. template<class U, class... Args> constexpr T& emplace(initializer_list<U> il, Args&&... args);
Constraints:
is_constructible_v<T, initializer_list<U>&, Args...> is
true. Effects: Calls
*this = nullopt. Then direct-non-list-initializes
val with
il, std::forward<Args>(args)....Postconditions:
*this contains a value
. Throws: Any exception thrown by the selected constructor of
T. Remarks: If an exception is thrown during the call to
T's constructor,
*this does not contain a value, and
the previous
val (if any) has been destroyed
. constexpr void swap(optional& rhs) noexcept(see below);
Mandates:
is_move_constructible_v<T> is
true. Effects: See Table Clause
71. Table
71 —
optional::swap(optional&) effects
[tab:optional.swap] | | | *this does not contain a value |
| | | direct-non-list-initializes val
with std::move(rhs.val),
followed by rhs.val.T::~T();
postcondition is that *this contains a value and rhs does not contain a value |
rhs does not contain a value | | direct-non-list-initializes rhs.val
with std::move(val),
followed by val.T::~T();
postcondition is that *this does not contain a value and rhs contains a value | |
Throws: Any exceptions thrown by the operations in the relevant part of Table Clause
71. Remarks: The exception specification is equivalent to:
is_nothrow_move_constructible_v<T> && is_nothrow_swappable_v<T>
If any exception is thrown, the results of the expressions
this->has_value() and
rhs.has_value() remain unchanged
. If an exception is thrown during the call to function
swap,
the states of
val and
rhs.val are determined by the exception safety guarantee of
swap for lvalues of
T. If an exception is thrown during the call to
T's move constructor,
the states of
val and
rhs.val are determined by the exception safety guarantee of
T's move constructor
.using iterator = implementation-defined;
using const_iterator = implementation-defined;
The reference type is
T& for
iterator and
const T& for
const_iterator. All requirements on container iterators (
[container.reqmts]) apply to
optional::iterator and
optional::const_iterator as well
.Any operation that initializes or destroys the contained value of an optional object invalidates all iterators into that object
.constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
Returns: If
has_value() is
true,
an iterator referring to the contained value
. Otherwise, a past-the-end iterator value
.constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
Returns:
begin() + has_value(). constexpr const T* operator->() const noexcept;
constexpr T* operator->() noexcept;
Hardened preconditions:
has_value() is
true. Remarks: These functions are constexpr functions
. constexpr const T& operator*() const & noexcept;
constexpr T& operator*() & noexcept;
Hardened preconditions:
has_value() is
true. Remarks: These functions are constexpr functions
. constexpr T&& operator*() && noexcept;
constexpr const T&& operator*() const && noexcept;
Hardened preconditions:
has_value() is
true. Effects: Equivalent to: return std::move(val);
constexpr explicit operator bool() const noexcept;
Returns:
true if and only if
*this contains a value
. Remarks: This function is a constexpr function
. constexpr bool has_value() const noexcept;
Returns:
true if and only if
*this contains a value
. Remarks: This function is a constexpr function
. constexpr const T& value() const &;
constexpr T& value() &;
Effects: Equivalent to:
return has_value() ? val : throw bad_optional_access();
constexpr T&& value() &&;
constexpr const T&& value() const &&;
Effects: Equivalent to:
return has_value() ? std::move(val) : throw bad_optional_access();
template<class U = remove_cv_t<T>> constexpr T value_or(U&& v) const &;
Mandates:
is_copy_constructible_v<T> && is_convertible_v<U&&, T> is
true. Effects: Equivalent to:
return has_value() ? val : static_cast<T>(std::forward<U>(v));
template<class U = remove_cv_t<T>> constexpr T value_or(U&& v) &&;
Mandates:
is_move_constructible_v<T> && is_convertible_v<U&&, T> is
true. Effects: Equivalent to:
return has_value() ? std::move(val) : static_cast<T>(std::forward<U>(v));
template<class F> constexpr auto and_then(F&& f) &;
template<class F> constexpr auto and_then(F&& f) const &;
Let
U be
invoke_result_t<F, decltype((val))>.Mandates:
remove_cvref_t<U> is a specialization of
optional. Effects: Equivalent to:
if (*this) {
return invoke(std::forward<F>(f), val);
} else {
return remove_cvref_t<U>();
}
template<class F> constexpr auto and_then(F&& f) &&;
template<class F> constexpr auto and_then(F&& f) const &&;
Let
U be
invoke_result_t<F, decltype(std::move(val))>.Mandates:
remove_cvref_t<U> is a specialization of
optional. Effects: Equivalent to:
if (*this) {
return invoke(std::forward<F>(f), std::move(val));
} else {
return remove_cvref_t<U>();
}
Let
U be
remove_cv_t<invoke_result_t<F, decltype((val))>>.Mandates:
U is a valid contained type for
optional. The declaration
U u(invoke(std::forward<F>(f), val));
is well-formed for some invented variable
u. Returns: If
*this contains a value, an
optional<U> object
whose contained value is direct-non-list-initialized with
invoke(std::forward<F>(f), val);
otherwise,
optional<U>(). Let
U be
remove_cv_t<invoke_result_t<F, decltype(std::move(val))>>.Mandates:
U is a valid contained type for
optional. The declaration
U u(invoke(std::forward<F>(f), std::move(val)));
is well-formed for some invented variable
u. Returns: If
*this contains a value, an
optional<U> object
whose contained value is direct-non-list-initialized with
invoke(std::forward<F>(f), std::move(val));
otherwise,
optional<U>(). template<class F> constexpr optional or_else(F&& f) const &;
Mandates:
is_same_v<remove_cvref_t<invoke_result_t<F>>, optional> is
true. Effects: Equivalent to:
if (*this) {
return *this;
} else {
return std::forward<F>(f)();
}
template<class F> constexpr optional or_else(F&& f) &&;
Mandates:
is_same_v<remove_cvref_t<invoke_result_t<F>>, optional> is
true. Effects: Equivalent to:
if (*this) {
return std::move(*this);
} else {
return std::forward<F>(f)();
}
constexpr void reset() noexcept;
Effects: If
*this contains a value, calls
val.T::~T() to destroy the contained value;
otherwise no effect
. Postconditions:
*this does not contain a value
. namespace std {
template<class T>
class optional<T&> {
public:
using value_type = T;
using iterator = implementation-defined;
constexpr optional() noexcept = default;
constexpr optional(nullopt_t) noexcept : optional() {}
constexpr optional(const optional& rhs) noexcept = default;
template<class Arg>
constexpr explicit optional(in_place_t, Arg&& arg);
template<class U>
constexpr explicit(see below) optional(U&& u) noexcept(see below);
template<class U>
constexpr explicit(see below) optional(optional<U>& rhs) noexcept(see below);
template<class U>
constexpr explicit(see below) optional(const optional<U>& rhs) noexcept(see below);
template<class U>
constexpr explicit(see below) optional(optional<U>&& rhs) noexcept(see below);
template<class U>
constexpr explicit(see below) optional(const optional<U>&& rhs) noexcept(see below);
constexpr ~optional() = default;
constexpr optional& operator=(nullopt_t) noexcept;
constexpr optional& operator=(const optional& rhs) noexcept = default;
template<class U> constexpr T& emplace(U&& u) noexcept(see below);
constexpr void swap(optional& rhs) noexcept;
constexpr auto begin() const noexcept;
constexpr auto end() const noexcept;
constexpr T* operator->() const noexcept;
constexpr T& operator*() const noexcept;
constexpr explicit operator bool() const noexcept;
constexpr bool has_value() const noexcept;
constexpr T& value() const;
template<class U = remove_cv_t<T>>
constexpr remove_cv_t<T> value_or(U&& u) const;
template<class F> constexpr auto and_then(F&& f) const;
template<class F> constexpr optional<invoke_result_t<F, T&>> transform(F&& f) const;
template<class F> constexpr optional or_else(F&& f) const;
constexpr void reset() noexcept;
private:
T* val = nullptr;
template<class U>
constexpr void convert-ref-init-val(U&& u);
};
}
An object of type
optional<T&>
contains a value
if and only if
val != nullptr is
true. When an
optional<T&> contains a value,
the
contained value
is a reference to
*val.Each type
optional<T&> is a trivially copyable class (
[class.prop])
.template<class Arg>
constexpr explicit optional(in_place_t, Arg&& arg);
Constraints:
- is_constructible_v<T&, Arg> is true, and
- reference_constructs_from_temporary_v<T&, Arg> is false.
Effects: Equivalent to:
convert-ref-init-val(std::forward<Arg>(arg)). Postconditions:
*this contains a value
. template<class U>
constexpr explicit(!is_convertible_v<U, T&>)
optional(U&& u) noexcept(is_nothrow_constructible_v<T&, U>);
Constraints:
- is_same_v<remove_cvref_t<U>, optional> is false,
- is_same_v<remove_cvref_t<U>, in_place_t> is false, and
- is_constructible_v<T&, U> is true.
Effects: Equivalent to:
convert-ref-init-val(std::forward<U>(u)). Postconditions:
*this contains a value
. Remarks: This constructor is defined as deleted if
reference_constructs_from_temporary_v<T&, U>
is
true. template<class U>
constexpr explicit(!is_convertible_v<U&, T&>)
optional(optional<U>& rhs) noexcept(is_nothrow_constructible_v<T&, U&>);
Constraints:
- is_same_v<remove_cv_t<T>, optional<U>> is false,
- is_same_v<T&, U> is false, and
- is_constructible_v<T&, U&> is true.
Effects: Equivalent to:
if (rhs.has_value()) convert-ref-init-val(rhs.operator*());
Remarks: This constructor is defined as deleted if
reference_constructs_from_temporary_v<T&, U&>
is
true. template<class U>
constexpr explicit(!is_convertible_v<const U&, T&>)
optional(const optional<U>& rhs) noexcept(is_nothrow_constructible_v<T&, const U&>);
Constraints:
- is_same_v<remove_cv_t<T>, optional<U>> is false,
- is_same_v<T&, U> is false, and
- is_constructible_v<T&, const U&> is true.
Effects: Equivalent to:
if (rhs.has_value()) convert-ref-init-val(rhs.operator*());
Remarks: This constructor is defined as deleted if
reference_constructs_from_temporary_v<T&, const U&>
is
true. template<class U>
constexpr explicit(!is_convertible_v<U, T&>)
optional(optional<U>&& rhs) noexcept(is_nothrow_constructible_v<T&, U>);
Constraints:
- is_same_v<remove_cv_t<T>, optional<U>> is false,
- is_same_v<T&, U> is false, and
- is_constructible_v<T&, U> is true.
Effects: Equivalent to:
if (rhs.has_value()) convert-ref-init-val(std::move(rhs).operator*());
Remarks: This constructor is defined as deleted if
reference_constructs_from_temporary_v<T&, U>
is
true. template<class U>
constexpr explicit(!is_convertible_v<const U, T&>)
optional(const optional<U>&& rhs) noexcept(is_nothrow_constructible_v<T&, const U>);
Constraints:
- is_same_v<remove_cv_t<T>, optional<U>> is false,
- is_same_v<T&, U> is false, and
- is_constructible_v<T&, const U> is true.
Effects: Equivalent to:
if (rhs.has_value()) convert-ref-init-val(std::move(rhs).operator*());
Remarks: This constructor is defined as deleted if
reference_constructs_from_temporary_v<T&, const U>
is
true. constexpr optional& operator=(nullopt_t) noexcept;
Effects: Assigns
nullptr to
val. Postconditions:
*this does not contain a value
. template<class U>
constexpr T& emplace(U&& u) noexcept(is_nothrow_constructible_v<T&, U>);
Constraints:
- is_constructible_v<T&, U> is true, and
- reference_constructs_from_temporary_v<T&, U> is false.
Effects: Equivalent to:
convert-ref-init-val(std::forward<U>(u)). constexpr void swap(optional& rhs) noexcept;
Effects: Equivalent to:
std::swap(val, rhs.val). using iterator = implementation-defined;
The reference type is
T& for
iterator. constexpr auto begin() const noexcept;
Constraints:
T is an object type other than an array of unknown bound
. Returns: An object
i of type
iterator, such that
i is an iterator referring to
*val
if
has_value() is
true, and
a past-the-end iterator value otherwise
. constexpr auto end() const noexcept;
Constraints:
T is an object type other than an array of unknown bound
. Returns:
begin() + has_value(). constexpr T* operator->() const noexcept;
Hardened preconditions:
has_value() is
true. constexpr T& operator*() const noexcept;
Hardened preconditions:
has_value() is
true. constexpr explicit operator bool() const noexcept;
constexpr bool has_value() const noexcept;
constexpr T& value() const;
Effects: Equivalent to:
return has_value() ? *val : throw bad_optional_access();
template<class U = remove_cv_t<T>> constexpr remove_cv_t<T> value_or(U&& u) const;
Constraints:
T is a non-array object type
. Mandates:
is_constructible_v<X, T&> && is_convertible_v<U, X> is
true. Effects: Equivalent to:
return has_value() ? *val : static_cast<X>(std::forward<U>(u));
Remarks: The return type is unspecified if
T is an array type or a non-object type
. [
Note 1:
This is to avoid the declaration being ill-formed
. —
end note]
template<class F> constexpr auto and_then(F&& f) const;
Let
U be
invoke_result_t<F, T&>.Mandates:
remove_cvref_t<U> is a specialization of
optional. Effects: Equivalent to:
if (has_value()) {
return invoke(std::forward<F>(f), *val);
} else {
return remove_cvref_t<U>();
}
template<class F>
constexpr optional<remove_cv_t<invoke_result_t<F, T&>>> transform(F&& f) const;
Let
U be
remove_cv_t<invoke_result_t<F, T&>>.Mandates:
U is a valid contained type for
optional. The declaration
U u(invoke(std::forward<F>(f), *val));
is well-formed for some invented variable
u. Returns: If
*this contains a value, an
optional<U> object
whose contained value is direct-non-list-initialized with
invoke(std::forward<F>(f), *val);
otherwise,
optional<U>(). template<class F> constexpr optional or_else(F&& f) const;
Mandates:
is_same_v<remove_cvref_t<invoke_result_t<F>>, optional> is
true. Effects: Equivalent to:
if (has_value()) {
return *val;
} else {
return std::forward<F>(f)();
}
constexpr void reset() noexcept;
Effects: Assigns
nullptr to
val. Postconditions:
*this does not contain a value
. template<class U>
constexpr void convert-ref-init-val(U&& u);
Effects: Creates a variable
r as if by
T& r(std::forward<U>(u));
and then initializes
val with
addressof(r). struct nullopt_t{see below};
inline constexpr nullopt_t nullopt(unspecified);
The struct
nullopt_t is an empty class type used as a unique type to indicate the state of not containing a value for
optional objects
. In particular,
optional<T> has a constructor with
nullopt_t as a single argument;
this indicates that an optional object not containing a value shall be constructed
.Type
nullopt_t does not have
a default constructor or an initializer-list constructor, and
is not an aggregate
. namespace std {
class bad_optional_access : public exception {
public:
constexpr const char* what() const noexcept override;
};
}
The class
bad_optional_access defines the type of objects thrown as exceptions to report the situation where an attempt is made to access the value of an optional object that does not contain a value
.constexpr const char* what() const noexcept override;
Returns: An
implementation-defined
ntbs,
which during constant evaluation is encoded with
the ordinary literal encoding (
[lex.ccon])
. template<class T, class U> constexpr bool operator==(const optional<T>& x, const optional<U>& y);
Constraints: The expression
*x == *y is well-formed and
its result is convertible to
bool. Returns: If
x.has_value() != y.has_value(),
false; otherwise if
x.has_value() == false,
true; otherwise
*x == *y. Remarks: Specializations of this function template
for which
*x == *y is a core constant expression
are constexpr functions
. template<class T, class U> constexpr bool operator!=(const optional<T>& x, const optional<U>& y);
Constraints: The expression
*x != *y is well-formed and
its result is convertible to
bool. Returns: If
x.has_value() != y.has_value(),
true;
otherwise, if
x.has_value() == false,
false;
otherwise
*x != *y. Remarks: Specializations of this function template
for which
*x != *y is a core constant expression
are constexpr functions
. template<class T, class U> constexpr bool operator<(const optional<T>& x, const optional<U>& y);
Constraints:
*x < *y is well-formed
and its result is convertible to
bool. Returns: If
!y,
false;
otherwise, if
!x,
true;
otherwise
*x < *y. Remarks: Specializations of this function template
for which
*x < *y is a core constant expression
are constexpr functions
. template<class T, class U> constexpr bool operator>(const optional<T>& x, const optional<U>& y);
Constraints: The expression
*x > *y is well-formed and
its result is convertible to
bool. Returns: If
!x,
false;
otherwise, if
!y,
true;
otherwise
*x > *y. Remarks: Specializations of this function template
for which
*x > *y is a core constant expression
are constexpr functions
. template<class T, class U> constexpr bool operator<=(const optional<T>& x, const optional<U>& y);
Constraints: The expression
*x <= *y is well-formed and
its result is convertible to
bool. Returns: If
!x,
true;
otherwise, if
!y,
false;
otherwise
*x <= *y. Remarks: Specializations of this function template
for which
*x <= *y is a core constant expression
are constexpr functions
. template<class T, class U> constexpr bool operator>=(const optional<T>& x, const optional<U>& y);
Constraints: The expression
*x >= *y is well-formed and
its result is convertible to
bool. Returns: If
!y,
true;
otherwise, if
!x,
false;
otherwise
*x >= *y. Remarks: Specializations of this function template
for which
*x >= *y is a core constant expression
are constexpr functions
. template<class T, three_way_comparable_with<T> U>
constexpr compare_three_way_result_t<T, U>
operator<=>(const optional<T>& x, const optional<U>& y);
Returns: If
x && y,
*x <=> *y; otherwise
x.has_value() <=> y.has_value(). Remarks: Specializations of this function template
for which
*x <=> *y is a core constant expression
are constexpr functions
. template<class T> constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept;
template<class T> constexpr strong_ordering operator<=>(const optional<T>& x, nullopt_t) noexcept;
Returns:
x.has_value() <=> false. template<class T, class U> constexpr bool operator==(const optional<T>& x, const U& v);
Constraints:
U is not a specialization of
optional. The expression
*x == v is well-formed and
its result is convertible to
bool. Effects: Equivalent to:
if (x.has_value())
return *x == v;
return false;
template<class T, class U> constexpr bool operator==(const T& v, const optional<U>& x);
Constraints:
T is not a specialization of
optional. The expression
v == *x is well-formed and
its result is convertible to
bool.Effects: Equivalent to:
if (x.has_value())
return v == *x;
return false;
template<class T, class U> constexpr bool operator!=(const optional<T>& x, const U& v);
Constraints:
U is not a specialization of
optional. The expression
*x != v is well-formed and
its result is convertible to
bool.Effects: Equivalent to:
if (x.has_value())
return *x != v;
return true;
template<class T, class U> constexpr bool operator!=(const T& v, const optional<U>& x);
Constraints:
T is not a specialization of
optional. The expression
v != *x is well-formed and
its result is convertible to
bool.Effects: Equivalent to:
if (x.has_value())
return v != *x;
return true;
template<class T, class U> constexpr bool operator<(const optional<T>& x, const U& v);
Constraints:
U is not a specialization of
optional. The expression
*x < v is well-formed and
its result is convertible to
bool.Effects: Equivalent to:
if (x.has_value())
return *x < v;
return true;
template<class T, class U> constexpr bool operator<(const T& v, const optional<U>& x);
Constraints:
T is not a specialization of
optional. The expression
v < *x is well-formed and
its result is convertible to
bool.Effects: Equivalent to:
if (x.has_value())
return v < *x;
return false;
template<class T, class U> constexpr bool operator>(const optional<T>& x, const U& v);
Constraints:
U is not a specialization of
optional. The expression
*x > v is well-formed and
its result is convertible to
bool.Effects: Equivalent to:
if (x.has_value())
return *x > v;
return false;
template<class T, class U> constexpr bool operator>(const T& v, const optional<U>& x);
Constraints:
T is not a specialization of
optional. The expression
v > *x is well-formed and
its result is convertible to
bool.Effects: Equivalent to:
if (x.has_value())
return v > *x;
return true;
template<class T, class U> constexpr bool operator<=(const optional<T>& x, const U& v);
Constraints:
U is not a specialization of
optional. The expression
*x <= v is well-formed and
its result is convertible to
bool.Effects: Equivalent to:
if (x.has_value())
return *x <= v;
return true;
template<class T, class U> constexpr bool operator<=(const T& v, const optional<U>& x);
Constraints:
T is not a specialization of
optional. The expression
v <= *x is well-formed and
its result is convertible to
bool.Effects: Equivalent to:
if (x.has_value())
return v <= *x;
return false;
template<class T, class U> constexpr bool operator>=(const optional<T>& x, const U& v);
Constraints:
U is not a specialization of
optional. The expression
*x >= v is well-formed and
its result is convertible to
bool.Effects: Equivalent to:
if (x.has_value())
return *x >= v;
return false;
template<class T, class U> constexpr bool operator>=(const T& v, const optional<U>& x);
Constraints:
T is not a specialization of
optional. The expression
v >= *x is well-formed and
its result is convertible to
bool.Effects: Equivalent to:
if (x.has_value())
return v >= *x;
return true;
Effects: Equivalent to: return x.has_value() ? *x <=> v : strong_ordering::less;
template<class T>
constexpr void swap(optional<T>& x, optional<T>& y) noexcept(noexcept(x.swap(y)));
Constraints:
is_reference_v<T> || (is_move_constructible_v<T> && is_swappable_v<T>)
is
true. Effects: Calls
x.swap(y). template<class T> constexpr optional<decay_t<T>> make_optional(T&& v);
Effects: Equivalent to: return optional<decay_t<T>>(std::forward<T>(v));
template<class T, class...Args>
constexpr optional<T> make_optional(Args&&... args);
Effects: Equivalent to: return optional<T>(in_place, std::forward<Args>(args)...);
template<class T, class U, class... Args>
constexpr optional<T> make_optional(initializer_list<U> il, Args&&... args);
Effects: Equivalent to: return optional<T>(in_place, il, std::forward<Args>(args)...);
template<class T> struct hash<optional<T>>;
The specialization
hash<optional<T>> is enabled (
[unord.hash])
if and only if
hash<remove_const_t<T>> is enabled
. When enabled, for an object
o of type
optional<T>,
if
o.has_value() == true, then
hash<optional<T>>()(o)
evaluates to the same value as
hash<remove_const_t<T>>()(*o);
otherwise it evaluates to an unspecified value
. The member functions are not guaranteed to be
noexcept.A variant object holds and manages the lifetime of a value
. If the
variant holds a value, that value's type has to be one
of the template argument types given to
variant. These template arguments are called alternatives
.
#include <compare>
namespace std {
template<class... Types>
class variant;
template<class T> struct variant_size;
template<class T> struct variant_size<const T>;
template<class T>
constexpr size_t variant_size_v = variant_size<T>::value;
template<class... Types>
struct variant_size<variant<Types...>>;
template<size_t I, class T> struct variant_alternative;
template<size_t I, class T> struct variant_alternative<I, const T>;
template<size_t I, class T>
using variant_alternative_t = variant_alternative<I, T>::type;
template<size_t I, class... Types>
struct variant_alternative<I, variant<Types...>>;
inline constexpr size_t variant_npos = -1;
template<class T, class... Types>
constexpr bool holds_alternative(const variant<Types...>&) noexcept;
template<size_t I, class... Types>
constexpr variant_alternative_t<I, variant<Types...>>&
get(variant<Types...>&);
template<size_t I, class... Types>
constexpr variant_alternative_t<I, variant<Types...>>&&
get(variant<Types...>&&);
template<size_t I, class... Types>
constexpr const variant_alternative_t<I, variant<Types...>>&
get(const variant<Types...>&);
template<size_t I, class... Types>
constexpr const variant_alternative_t<I, variant<Types...>>&&
get(const variant<Types...>&&);
template<class T, class... Types>
constexpr T& get(variant<Types...>&);
template<class T, class... Types>
constexpr T&& get(variant<Types...>&&);
template<class T, class... Types>
constexpr const T& get(const variant<Types...>&);
template<class T, class... Types>
constexpr const T&& get(const variant<Types...>&&);
template<size_t I, class... Types>
constexpr add_pointer_t<variant_alternative_t<I, variant<Types...>>>
get_if(variant<Types...>*) noexcept;
template<size_t I, class... Types>
constexpr add_pointer_t<const variant_alternative_t<I, variant<Types...>>>
get_if(const variant<Types...>*) noexcept;
template<class T, class... Types>
constexpr add_pointer_t<T>
get_if(variant<Types...>*) noexcept;
template<class T, class... Types>
constexpr add_pointer_t<const T>
get_if(const variant<Types...>*) noexcept;
template<class... Types>
constexpr bool operator==(const variant<Types...>&, const variant<Types...>&);
template<class... Types>
constexpr bool operator!=(const variant<Types...>&, const variant<Types...>&);
template<class... Types>
constexpr bool operator<(const variant<Types...>&, const variant<Types...>&);
template<class... Types>
constexpr bool operator>(const variant<Types...>&, const variant<Types...>&);
template<class... Types>
constexpr bool operator<=(const variant<Types...>&, const variant<Types...>&);
template<class... Types>
constexpr bool operator>=(const variant<Types...>&, const variant<Types...>&);
template<class... Types> requires (three_way_comparable<Types> && ...)
constexpr common_comparison_category_t<compare_three_way_result_t<Types>...>
operator<=>(const variant<Types...>&, const variant<Types...>&);
template<class Visitor, class... Variants>
constexpr see below visit(Visitor&&, Variants&&...);
template<class R, class Visitor, class... Variants>
constexpr R visit(Visitor&&, Variants&&...);
struct monostate;
constexpr bool operator==(monostate, monostate) noexcept;
constexpr strong_ordering operator<=>(monostate, monostate) noexcept;
template<class... Types>
constexpr void swap(variant<Types...>&, variant<Types...>&) noexcept(see below);
class bad_variant_access;
template<class T> struct hash;
template<class... Types> struct hash<variant<Types...>>;
template<> struct hash<monostate>;
}
namespace std {
template<class... Types>
class variant {
public:
constexpr variant() noexcept(see below);
constexpr variant(const variant&) noexcept(see below);
constexpr variant(variant&&) noexcept(see below);
template<class T>
constexpr variant(T&&) noexcept(see below);
template<class T, class... Args>
constexpr explicit variant(in_place_type_t<T>, Args&&...);
template<class T, class U, class... Args>
constexpr explicit variant(in_place_type_t<T>, initializer_list<U>, Args&&...);
template<size_t I, class... Args>
constexpr explicit variant(in_place_index_t<I>, Args&&...);
template<size_t I, class U, class... Args>
constexpr explicit variant(in_place_index_t<I>, initializer_list<U>, Args&&...);
constexpr ~variant();
constexpr variant& operator=(const variant&);
constexpr variant& operator=(variant&&) noexcept(see below);
template<class T> constexpr variant& operator=(T&&) noexcept(see below);
template<class T, class... Args>
constexpr T& emplace(Args&&...);
template<class T, class U, class... Args>
constexpr T& emplace(initializer_list<U>, Args&&...);
template<size_t I, class... Args>
constexpr variant_alternative_t<I, variant<Types...>>& emplace(Args&&...);
template<size_t I, class U, class... Args>
constexpr variant_alternative_t<I, variant<Types...>>&
emplace(initializer_list<U>, Args&&...);
constexpr bool valueless_by_exception() const noexcept;
constexpr size_t index() const noexcept;
constexpr void swap(variant&) noexcept(see below);
template<class Self, class Visitor>
constexpr decltype(auto) visit(this Self&&, Visitor&&);
template<class R, class Self, class Visitor>
constexpr R visit(this Self&&, Visitor&&);
};
}
Any instance of
variant at any given time either holds a value
of one of its alternative types or holds no value
. When an instance of
variant holds a value of alternative type
T,
it means that a value of type
T, referred to as the
variant
object's
contained value,
is nested within (
[intro.object]) the
variant object
.A program that instantiates the definition of
variant with
no template arguments is ill-formed
.If a program declares an explicit or partial specialization of
variant,
the program is ill-formed, no diagnostic required
.In the descriptions that follow, let
i be in the range [
0, sizeof...(Types)),
and
Ti be the
ith type in
Types.constexpr variant() noexcept(see below);
Constraints:
is_default_constructible_v<T0> is
true. Effects: Constructs a
variant holding a value-initialized value of type
T0. Postconditions:
valueless_by_exception() is
false and
index() is
0. Throws: Any exception thrown by the value-initialization of
T0. Remarks: This function is
constexpr if and only if the
value-initialization of the alternative type
T0
would be constexpr-suitable (
[dcl.constexpr])
. The exception specification is equivalent to
is_nothrow_default_constructible_v<T0>. [
Note 1:
See also class
monostate. —
end note]
constexpr variant(const variant& w) noexcept(see below);
Effects: If
w holds a value, initializes the
variant to hold the same
alternative as
w and direct-initializes the contained value
with
GET<j>(w), where
j is
w.index(). Otherwise, initializes the
variant to not hold a value
.Throws: Any exception thrown by
the initialization of the contained value
. Remarks: This constructor is defined as deleted unless
is_copy_constructible_v<Ti> is
true for all
i. If
is_trivially_copy_constructible_v<Ti>
is
true for all
i, this constructor is trivial
. The exception specification is equivalent to the logical
and of
is_nothrow_copy_constructible_v<Ti> for all
i.constexpr variant(variant&& w) noexcept(see below);
Constraints:
is_move_constructible_v<Ti> is
true for all
i. Effects: If
w holds a value, initializes the
variant to hold the same
alternative as
w and direct-initializes the contained value with
GET<j>(std::move(w)), where
j is
w.index(). Otherwise, initializes the
variant to not hold a value
.Throws: Any exception thrown by
the initialization of the contained value
. Remarks: The exception specification is equivalent to the logical
and of
is_nothrow_move_constructible_v<Ti> for all
i. If
is_trivially_move_constructible_v<Ti>
is
true for all
i, this constructor is trivial
.template<class T> constexpr variant(T&& t) noexcept(see below);
Let
Tj be a type that is determined as follows:
build an imaginary function
FUN(Ti)
for each alternative type
Ti
for which
Ti x[] = {std::forward<T>(t)};
is well-formed for some invented variable
x. The overload
FUN(Tj) selected by overload
resolution for the expression
FUN(std::forward<T>(t)) defines
the alternative
Tj which is the type of the contained value after
construction
.Constraints:
- sizeof...(Types) is nonzero,
- is_same_v<remove_cvref_t<T>, variant> is false,
- remove_cvref_t<T> is neither
a specialization of in_place_type_t nor
a specialization of in_place_index_t,
- is_constructible_v<Tj, T> is true, and
- the expression FUN(std::forward<T>(t))
(with FUN being the above-mentioned set of
imaginary functions) is well-formed.
[
Note 2:
variant<string, string> v("abc");
is ill-formed, as both alternative types have an equally viable constructor
for the argument
. —
end note]
Effects: Initializes
*this to hold the alternative type
Tj and
direct-non-list-initializes the contained value with
std::forward<T>(t). Postconditions:
holds_alternative<Tj>(*this) is
true. Throws: Any exception thrown by
the initialization of the contained value
. Remarks: The exception specification is equivalent to
is_nothrow_constructible_v<Tj, T>. If
Tj's selected constructor is a constexpr constructor,
this constructor is a constexpr constructor
.template<class T, class... Args> constexpr explicit variant(in_place_type_t<T>, Args&&... args);
Constraints:
- There is exactly one occurrence of T in Types... and
- is_constructible_v<T, Args...> is true.
Effects: Direct-non-list-initializes the contained value of type
T
with
std::forward<Args>(args).... Postconditions:
holds_alternative<T>(*this) is
true. Throws: Any exception thrown by
the initialization of the contained value
. Remarks: If
T's selected constructor is a constexpr constructor, this
constructor is a constexpr constructor
. template<class T, class U, class... Args>
constexpr explicit variant(in_place_type_t<T>, initializer_list<U> il, Args&&... args);
Constraints:
- There is exactly one occurrence of T in Types... and
- is_constructible_v<T, initializer_list<U>&, Args...> is true.
Effects: Direct-non-list-initializes the contained value of type
T
with
il, std::forward<Args>(args).... Postconditions:
holds_alternative<T>(*this) is
true. Throws: Any exception thrown by
the initialization of the contained value
. Remarks: If
T's selected constructor is a constexpr constructor, this
constructor is a constexpr constructor
. template<size_t I, class... Args> constexpr explicit variant(in_place_index_t<I>, Args&&... args);
Constraints:
- I is less than sizeof...(Types) and
- is_constructible_v<TI, Args...> is true.
Effects: Direct-non-list-initializes the contained value of type
TI
with
std::forward<Args>(args).... Postconditions:
index() is
I. Throws: Any exception thrown by
the initialization of the contained value
. Remarks: If
TI's selected constructor is a constexpr constructor, this
constructor is a constexpr constructor
. template<size_t I, class U, class... Args>
constexpr explicit variant(in_place_index_t<I>, initializer_list<U> il, Args&&... args);
Constraints:
- I is less than sizeof...(Types) and
- is_constructible_v<TI, initializer_list<U>&, Args...> is true.
Effects: Direct-non-list-initializes the contained value of type
TI
with
il, std::forward<Args>(args).... Postconditions:
index() is
I. Throws: Any exception thrown by
the initialization of the contained value
. Remarks: If
TI's selected constructor is a constexpr constructor, this
constructor is a constexpr constructor
. Effects: If
valueless_by_exception() is
false,
destroys the currently contained value
. Remarks: If
is_trivially_destructible_v<Ti> is
true for all
Ti,
then this destructor is trivial
. constexpr variant& operator=(const variant& rhs);
Effects:
If neither
*this nor
rhs holds a value, there is no effect
.Otherwise, if
*this holds a value but
rhs does not, destroys the value
contained in
*this and sets
*this to not hold a value
.Otherwise, if
index() == j, assigns the value contained in
rhs
to the value contained in
*this.Otherwise, if either
is_nothrow_copy_constructible_v<Tj>
is
true or
is_nothrow_move_constructible_v<Tj> is
false,
equivalent to
emplace<j>(GET<j>(rhs)).Otherwise, equivalent to
operator=(variant(rhs)).
Postconditions:
index() == rhs.index(). Remarks: This operator is defined as deleted unless
is_copy_constructible_v<Ti> &&
is_copy_assignable_v<Ti>
is
true for all
i. If
is_trivially_copy_constructible_v<Ti> &&
is_trivially_copy_assignable_v<Ti> &&
is_trivially_destructible_v<Ti>
is
true for all
i, this assignment operator is trivial
.constexpr variant& operator=(variant&& rhs) noexcept(see below);
Constraints:
is_move_constructible_v<Ti> &&
is_move_assignable_v<Ti> is
true for all
i. Effects:
If neither
*this nor
rhs holds a value, there is no effect
.Otherwise, if
*this holds a value but
rhs does not, destroys the value
contained in
*this and sets
*this to not hold a value
.Otherwise, if
index() == j, assigns
GET<j>(std::move(rhs)) to
the value contained in
*this.Otherwise, equivalent to
emplace<j>(GET<j>(std::move(rhs))).
Remarks: If
is_trivially_move_constructible_v<Ti> &&
is_trivially_move_assignable_v<Ti> &&
is_trivially_destructible_v<Ti>
is
true for all
i, this assignment operator is trivial
. The exception specification is equivalent to
is_nothrow_move_constructible_v<Ti> && is_nothrow_move_assignable_v<Ti> for all
i. If an exception is thrown during the call to
Tj's move construction
(with
j being
rhs.index()), the
variant will hold no value
.If an exception is thrown during the call to
Tj's move assignment,
the state of the contained value is as defined by the exception safety
guarantee of
Tj's move assignment;
index() will be
j.
template<class T> constexpr variant& operator=(T&& t) noexcept(see below);
Let
Tj be a type that is determined as follows:
build an imaginary function
FUN(Ti)
for each alternative type
Ti
for which
Ti x[] = {std::forward<T>(t)};
is well-formed for some invented variable
x. The overload
FUN(Tj) selected by overload
resolution for the expression
FUN(std::forward<T>(t)) defines
the alternative
Tj which is the type of the contained value after
assignment
.Constraints:
- is_same_v<remove_cvref_t<T>, variant> is false,
- is_assignable_v<Tj&, T> && is_constructible_v<Tj, T>
is true, and
- the expression FUN(std::forward<T>(t))
(with FUN being the above-mentioned set
of imaginary functions) is well-formed.
[
Note 1:
variant<string, string> v;
v = "abc";
is ill-formed, as both alternative types have an equally viable constructor
for the argument
. —
end note]
Effects:
If
*this holds a
Tj, assigns
std::forward<T>(t) to
the value contained in
*this.Otherwise, if
is_nothrow_constructible_v<Tj, T> ||
!is_nothrow_move_constructible_v<Tj> is
true,
equivalent to
emplace<j>(std::forward<T>(t)).Otherwise, equivalent to
emplace<j>(Tj(std::forward<T>(t))).
Postconditions:
holds_alternative<Tj>(*this) is
true, with
Tj
selected by the imaginary function overload resolution described above
. Remarks: The exception specification is equivalent to:
is_nothrow_assignable_v<Tj&, T> && is_nothrow_constructible_v<Tj, T>
If an exception is thrown during the assignment of
std::forward<T>(t)
to the value contained in
*this, the state of the contained value and
t are as defined by the exception safety guarantee of the assignment
expression;
valueless_by_exception() will be
false.If an exception is thrown during the initialization of the contained value,
the
variant object is permitted to not hold a value
.
template<class T, class... Args> constexpr T& emplace(Args&&... args);
Constraints:
is_constructible_v<T, Args...> is
true, and
T occurs exactly once in
Types. Effects: Equivalent to:
return emplace<I>(std::forward<Args>(args)...);
where
I is the zero-based index of
T in
Types. template<class T, class U, class... Args>
constexpr T& emplace(initializer_list<U> il, Args&&... args);
Constraints:
is_constructible_v<T, initializer_list<U>&, Args...> is
true,
and
T occurs exactly once in
Types. Effects: Equivalent to:
return emplace<I>(il, std::forward<Args>(args)...);
where
I is the zero-based index of
T in
Types. template<size_t I, class... Args>
constexpr variant_alternative_t<I, variant<Types...>>& emplace(Args&&... args);
Mandates:
I < sizeof...(Types). Constraints:
is_constructible_v<TI, Args...> is
true. Effects: Destroys the currently contained value if
valueless_by_exception()
is
false. Then direct-non-list-initializes the contained value of type
TI
with the arguments
std::forward<Args>(args)....Postconditions:
index() is
I. Returns: A reference to the new contained value
. Throws: Any exception thrown during the initialization of the contained value
. Remarks: If an exception is thrown during the initialization of the contained value,
the
variant is permitted to not hold a value
. template<size_t I, class U, class... Args>
constexpr variant_alternative_t<I, variant<Types...>>&
emplace(initializer_list<U> il, Args&&... args);
Mandates:
I < sizeof...(Types). Constraints:
is_constructible_v<TI, initializer_list<U>&, Args...> is
true. Effects: Destroys the currently contained value if
valueless_by_exception()
is
false. Then direct-non-list-initializes the contained value of type
TI
with
il, std::forward<Args>(args)....Postconditions:
index() is
I. Returns: A reference to the new contained value
. Throws: Any exception thrown during the initialization of the contained value
. Remarks: If an exception is thrown during the initialization of the contained value,
the
variant is permitted to not hold a value
. constexpr bool valueless_by_exception() const noexcept;
Effects: Returns
false if and only if the
variant holds a value
. [
Note 1:
It is possible for a
variant to hold no value
if an exception is thrown during a
type-changing assignment or emplacement
. The latter means that even a
variant<float, int> can become valueless_by_exception(), for
instance by
struct S { operator int() { throw 42; }};
variant<float, int> v{12.f};
v.emplace<1>(S());
—
end note]
constexpr size_t index() const noexcept;
Effects: If
valueless_by_exception() is
true, returns
variant_npos. Otherwise, returns the zero-based index of the alternative of the contained value
.constexpr void swap(variant& rhs) noexcept(see below);
Mandates:
is_move_constructible_v<Ti> is
true for all
i. Effects:
If
valueless_by_exception() && rhs.valueless_by_exception() no effect
.Otherwise, if
index() == rhs.index(), calls
swap(GET<i>(*this), GET<i>(rhs)) where
i is
index().Otherwise, exchanges values of
rhs and
*this.
Throws: If
index() == rhs.index(),
any exception thrown by
swap(GET<i>(*this), GET<i>(rhs))
with
i being
index(). Otherwise, any exception thrown by the move constructor
of
Ti or
Tj
with
i being
index() and
j being
rhs.index().Remarks: If an exception is thrown during the call to function
swap(GET<i>(*this), GET<i>(rhs)),
the states of the contained values of
*this and of
rhs are
determined by the exception safety guarantee of
swap for lvalues of
Ti with
i being
index(). If an exception is thrown during the exchange of the values of
*this
and
rhs, the states of the values of
*this and of
rhs
are determined by the exception safety guarantee of
variant's move constructor
. The exception specification is equivalent to the logical
and of
is_nothrow_move_constructible_v<Ti> && is_nothrow_swappable_v<Ti> for all
i.template<class T> struct variant_size;
All specializations of
variant_size meet the
Cpp17UnaryTypeTrait requirements (
[meta.rqmts])
with a base characteristic of
integral_constant<size_t, N> for some
N.template<class T> struct variant_size<const T>;
Let
VS denote
variant_size<T> of the cv-unqualified
type
T. Then each specialization of the template meets the
Cpp17UnaryTypeTrait requirements (
[meta.rqmts]) with a
base characteristic of
integral_constant<size_t, VS::value>.template<class... Types>
struct variant_size<variant<Types...>> : integral_constant<size_t, sizeof...(Types)> { };
template<size_t I, class T> struct variant_alternative<I, const T>;
Let
VA denote
variant_alternative<I, T> of the
cv-unqualified type
T. variant_alternative<I, variant<Types...>>::type
Mandates:
I < sizeof...(Types). template<class T, class... Types>
constexpr bool holds_alternative(const variant<Types...>& v) noexcept;
Mandates: The type
T occurs exactly once in
Types. Returns:
true if
index() is equal to the zero-based index of
T in
Types. template<size_t I, class... Types>
constexpr variant_alternative_t<I, variant<Types...>>&
GET(variant<Types...>& v);
template<size_t I, class... Types>
constexpr variant_alternative_t<I, variant<Types...>>&&
GET(variant<Types...>&& v);
template<size_t I, class... Types>
constexpr const variant_alternative_t<I, variant<Types...>>&
GET(const variant<Types...>& v);
template<size_t I, class... Types>
constexpr const variant_alternative_t<I, variant<Types...>>&&
GET(const variant<Types...>&& v);
Mandates:
I < sizeof...(Types). Preconditions:
v.index() is
I. Returns: A reference to the object stored in the
variant. template<size_t I, class... Types>
constexpr variant_alternative_t<I, variant<Types...>>& get(variant<Types...>& v);
template<size_t I, class... Types>
constexpr variant_alternative_t<I, variant<Types...>>&& get(variant<Types...>&& v);
template<size_t I, class... Types>
constexpr const variant_alternative_t<I, variant<Types...>>& get(const variant<Types...>& v);
template<size_t I, class... Types>
constexpr const variant_alternative_t<I, variant<Types...>>&& get(const variant<Types...>&& v);
Mandates:
I < sizeof...(Types). Effects: If
v.index() is
I, returns a reference to the object stored in
the
variant. Otherwise, throws an exception of type
bad_variant_access.template<class T, class... Types> constexpr T& get(variant<Types...>& v);
template<class T, class... Types> constexpr T&& get(variant<Types...>&& v);
template<class T, class... Types> constexpr const T& get(const variant<Types...>& v);
template<class T, class... Types> constexpr const T&& get(const variant<Types...>&& v);
Mandates: The type
T occurs exactly once in
Types. Effects: If
v holds a value of type
T, returns a reference to that value
. Otherwise, throws an exception of type
bad_variant_access.template<size_t I, class... Types>
constexpr add_pointer_t<variant_alternative_t<I, variant<Types...>>>
get_if(variant<Types...>* v) noexcept;
template<size_t I, class... Types>
constexpr add_pointer_t<const variant_alternative_t<I, variant<Types...>>>
get_if(const variant<Types...>* v) noexcept;
Mandates:
I < sizeof...(Types). Returns: A pointer to the value stored in the
variant, if
v != nullptr
and
v->index() == I. Otherwise, returns
nullptr.template<class T, class... Types>
constexpr add_pointer_t<T>
get_if(variant<Types...>* v) noexcept;
template<class T, class... Types>
constexpr add_pointer_t<const T>
get_if(const variant<Types...>* v) noexcept;
Mandates: The type
T occurs exactly once in
Types. Effects: Equivalent to:
return get_if<i>(v); with
i being the zero-based
index of
T in
Types. template<class... Types>
constexpr bool operator==(const variant<Types...>& v, const variant<Types...>& w);
Constraints:
GET<i>(v) == GET<i>(w) is a valid expression that is
convertible to
bool, for all
i. Returns: If
v.index() != w.index(),
false;
otherwise if
v.valueless_by_exception(),
true;
otherwise
GET<i>(v) == GET<i>(w) with
i being
v.index(). template<class... Types>
constexpr bool operator!=(const variant<Types...>& v, const variant<Types...>& w);
Constraints:
GET<i>(v) != GET<i>(w) is a valid expression that is
convertible to
bool, for all
i. Returns: If
v.index() != w.index(),
true;
otherwise if
v.valueless_by_exception(),
false;
otherwise
GET<i>(v) != GET<i>(w) with
i being
v.index(). template<class... Types>
constexpr bool operator<(const variant<Types...>& v, const variant<Types...>& w);
Constraints:
GET<i>(v) < GET<i>(w) is a valid expression that is
convertible to
bool, for all
i. Returns: If
w.valueless_by_exception(),
false;
otherwise if
v.valueless_by_exception(),
true;
otherwise, if
v.index() < w.index(),
true;
otherwise if
v.index() > w.index(),
false;
otherwise
GET<i>(v) < GET<i>(w) with
i being
v.index(). template<class... Types>
constexpr bool operator>(const variant<Types...>& v, const variant<Types...>& w);
Constraints:
GET<i>(v) > GET<i>(w) is a valid expression that is
convertible to
bool, for all
i. Returns: If
v.valueless_by_exception(),
false;
otherwise if
w.valueless_by_exception(),
true;
otherwise, if
v.index() > w.index(),
true;
otherwise if
v.index() < w.index(),
false;
otherwise
GET<i>(v) > GET<i>(w) with
i being
v.index(). template<class... Types>
constexpr bool operator<=(const variant<Types...>& v, const variant<Types...>& w);
Constraints:
GET<i>(v) <= GET<i>(w) is a valid expression that is
convertible to
bool, for all
i. Returns: If
v.valueless_by_exception(),
true;
otherwise if
w.valueless_by_exception(),
false;
otherwise, if
v.index() < w.index(),
true;
otherwise if
v.index() > w.index(),
false;
otherwise
GET<i>(v) <= GET<i>(w) with
i being
v.index(). template<class... Types>
constexpr bool operator>=(const variant<Types...>& v, const variant<Types...>& w);
Constraints:
GET<i>(v) >= GET<i>(w) is a valid expression that is
convertible to
bool, for all
i. Returns: If
w.valueless_by_exception(),
true;
otherwise if
v.valueless_by_exception(),
false;
otherwise, if
v.index() > w.index(),
true;
otherwise if
v.index() < w.index(),
false;
otherwise
GET<i>(v) >= GET<i>(w) with
i being
v.index(). template<class... Types> requires (three_way_comparable<Types> && ...)
constexpr common_comparison_category_t<compare_three_way_result_t<Types>...>
operator<=>(const variant<Types...>& v, const variant<Types...>& w);
Effects: Equivalent to:
if (v.valueless_by_exception() && w.valueless_by_exception())
return strong_ordering::equal;
if (v.valueless_by_exception()) return strong_ordering::less;
if (w.valueless_by_exception()) return strong_ordering::greater;
if (auto c = v.index() <=> w.index(); c != 0) return c;
return GET<i>(v) <=> GET<i>(w);
with
i being
v.index(). template<class Visitor, class... Variants>
constexpr see below visit(Visitor&& vis, Variants&&... vars);
template<class R, class Visitor, class... Variants>
constexpr R visit(Visitor&& vis, Variants&&... vars);
Let as-variant denote the following exposition-only function templates:
template<class... Ts>
constexpr auto&& as-variant(variant<Ts...>& var) { return var; }
template<class... Ts>
constexpr auto&& as-variant(const variant<Ts...>& var) { return var; }
template<class... Ts>
constexpr auto&& as-variant(variant<Ts...>&& var) { return std::move(var); }
template<class... Ts>
constexpr auto&& as-variant(const variant<Ts...>&& var) { return std::move(var); }
Let
n be
sizeof...(Variants). For each
0≤i<n, let
Vi denote the type
decltype(as-variant(std::forward<Variantsi>(varsi))).Constraints:
Vi is a valid type for all
0≤i<n. Let
V denote the pack of types
Vi.Let
m be a pack of
n values of type
size_t. Such a pack is valid if
0≤mi<variant_size_v<remove_reference_t<Vi>>
for all
0≤i<n. For each valid pack
m, let
e(m) denote the expression:
INVOKE(std::forward<Visitor>(vis), GET<m>(std::forward<V>(vars))...)
for the first form and
INVOKE<R>(std::forward<Visitor>(vis), GET<m>(std::forward<V>(vars))...)
for the second form
.Mandates: For each valid pack
m,
e(m) is a valid expression
. All such expressions are of the same type and value category
.Returns:
e(m), where
m is the pack for which
mi is
as-variant(varsi).index() for all
0≤i<n. The return type is
decltype(e(m))
for the first form
.Throws:
bad_variant_access if
(as-variant(vars).valueless_by_exception() || ...)
is
true. Complexity: For
n ≤ 1, the invocation of the callable object is
implemented in constant time, i.e., for
n=1, it does not depend on
the number of alternative types of
V0. For
n>1, the invocation of the callable object has
no complexity requirements
.template<class Self, class Visitor>
constexpr decltype(auto) visit(this Self&& self, Visitor&& vis);
Let
V be
OVERRIDE_REF(Self&&, COPY_CONST(remove_reference_t<Self>, variant)) (
[forward])
.Effects: Equivalent to: return std::visit(std::forward<Visitor>(vis), (V)self);
template<class R, class Self, class Visitor>
constexpr R visit(this Self&& self, Visitor&& vis);
Let
V be
OVERRIDE_REF(Self&&, COPY_CONST(remove_reference_t<Self>, variant)) (
[forward])
.Effects: Equivalent to: return std::visit<R>(std::forward<Visitor>(vis), (V)self);
The class
monostate can serve as a first alternative type for
a
variant to make the
variant type default constructible
.constexpr bool operator==(monostate, monostate) noexcept { return true; }
constexpr strong_ordering operator<=>(monostate, monostate) noexcept
{ return strong_ordering::equal; }
[
Note 1:
monostate objects have only a single state; they thus always compare equal
. —
end note]
template<class... Types>
constexpr void swap(variant<Types...>& v, variant<Types...>& w) noexcept(see below);
Constraints:
is_move_constructible_v<Ti> && is_swappable_v<Ti>
is
true for all
i. Effects: Equivalent to
v.swap(w). Remarks: The exception specification is equivalent to
noexcept(v.swap(w)).
namespace std {
class bad_variant_access : public exception {
public:
constexpr const char* what() const noexcept override;
};
}
Objects of type
bad_variant_access are thrown to report invalid
accesses to the value of a
variant object
.constexpr const char* what() const noexcept override;
Returns: An
implementation-defined
ntbs,
which during constant evaluation is encoded with
the ordinary literal encoding (
[lex.ccon])
. template<class... Types> struct hash<variant<Types...>>;
The specialization
hash<variant<Types...>> is enabled (
[unord.hash])
if and only if every specialization in
hash<remove_const_t<Types>>... is enabled
. The member functions are not guaranteed to be
noexcept.template<> struct hash<monostate>;
Subclause
[any] describes components that C++ programs may use to perform operations on objects of a discriminated type
.[
Note 1:
The discriminated type can contain values of different types but does not attempt conversion between them,
i.e.,
5 is held strictly as an
int and is not implicitly convertible either to
"5" or to
5.0. This indifference to interpretation but awareness of type effectively allows safe, generic containers of single values, with no scope for surprises from ambiguous conversions
. —
end note]
#include <initializer_list>
#include <typeinfo>
namespace std {
class bad_any_cast;
class any;
void swap(any& x, any& y) noexcept;
template<class T, class... Args>
any make_any(Args&&... args);
template<class T, class U, class... Args>
any make_any(initializer_list<U> il, Args&&... args);
template<class T>
T any_cast(const any& operand);
template<class T>
T any_cast(any& operand);
template<class T>
T any_cast(any&& operand);
template<class T>
const T* any_cast(const any* operand) noexcept;
template<class T>
T* any_cast(any* operand) noexcept;
}
namespace std {
class bad_any_cast : public bad_cast {
public:
const char* what() const noexcept override;
};
}
Objects of type
bad_any_cast are thrown by a failed
any_cast.const char* what() const noexcept override;
Returns: An
implementation-defined
ntbs. namespace std {
class any {
public:
constexpr any() noexcept;
any(const any& other);
any(any&& other) noexcept;
template<class T>
any(T&& value);
template<class T, class... Args>
explicit any(in_place_type_t<T>, Args&&...);
template<class T, class U, class... Args>
explicit any(in_place_type_t<T>, initializer_list<U>, Args&&...);
~any();
any& operator=(const any& rhs);
any& operator=(any&& rhs) noexcept;
template<class T>
any& operator=(T&& rhs);
template<class T, class... Args>
decay_t<T>& emplace(Args&&...);
template<class T, class U, class... Args>
decay_t<T>& emplace(initializer_list<U>, Args&&...);
void reset() noexcept;
void swap(any& rhs) noexcept;
bool has_value() const noexcept;
const type_info& type() const noexcept;
};
}
An object of class
any stores an instance of any type that meets the constructor requirements or it has no value,
and this is referred to as the
state of the class
any object
. Two states are equivalent if either they both have no value, or they both have a value and the contained values are equivalent
.The non-member
any_cast functions provide type-safe access to the contained value
.Implementations should avoid the use of dynamically allocated memory for a small contained value
. However, any such small-object optimization shall only be applied to types
T for which
is_nothrow_move_constructible_v<T> is
true. [
Example 1:
A contained value of type
int could be stored in an internal buffer,
not in separately-allocated memory
. —
end example]
constexpr any() noexcept;
Postconditions:
has_value() is
false. Effects: If
other.has_value() is
false, constructs an object that has no value
. Otherwise, equivalent to
any(in_place_type<T>, any_cast<const T&>(other))
where
T is the type of the contained value
.Throws: Any exceptions arising from calling the selected constructor for the contained value
. any(any&& other) noexcept;
Effects: If
other.has_value() is
false, constructs an object that has no value
. Otherwise, constructs an object of type
any that
contains either the contained value of
other, or
contains an object of the same type constructed from
the contained value of
other considering that contained value as an rvalue
.template<class T>
any(T&& value);
Constraints:
VT is not the same type as
any,
VT is not a specialization of
in_place_type_t,
and
is_copy_constructible_v<VT> is
true. Effects: Constructs an object of type
any that contains an object of type
VT direct-initialized with
std::forward<T>(value). Throws: Any exception thrown by the selected constructor of
VT. template<class T, class... Args>
explicit any(in_place_type_t<T>, Args&&... args);
Constraints:
is_copy_constructible_v<VT> is
true and
is_constructible_v<VT, Args...> is
true. Effects: Direct-non-list-initializes the contained value of type
VT
with
std::forward<Args>(args).... Postconditions:
*this contains a value of type
VT. Throws: Any exception thrown by the selected constructor of
VT. template<class T, class U, class... Args>
explicit any(in_place_type_t<T>, initializer_list<U> il, Args&&... args);
Constraints:
is_copy_constructible_v<VT> is
true and
is_constructible_v<VT, initializer_list<U>&, Args...> is
true. Effects: Direct-non-list-initializes the contained value of type
VT
with
il, std::forward<Args>(args).... Postconditions:
*this contains a value
. Throws: Any exception thrown by the selected constructor of
VT. Effects: As if by
reset(). any& operator=(const any& rhs);
Effects: As if by
any(rhs).swap(*this). No effects if an exception is thrown
.Throws: Any exceptions arising from the copy constructor for the contained value
. any& operator=(any&& rhs) noexcept;
Effects: As if by
any(std::move(rhs)).swap(*this). Postconditions: The state of
*this is equivalent to the original state of
rhs. template<class T>
any& operator=(T&& rhs);
Constraints:
VT is not the same type as
any and
is_copy_constructible_v<VT> is
true. Effects: Constructs an object
tmp of type
any that contains an object of type
VT direct-initialized with
std::forward<T>(rhs), and
tmp.swap(*this). No effects if an exception is thrown
.Throws: Any exception thrown by the selected constructor of
VT. template<class T, class... Args>
decay_t<T>& emplace(Args&&... args);
Constraints:
is_copy_constructible_v<VT> is
true and
is_constructible_v<VT, Args...> is
true. Then direct-non-list-initializes the contained value of type
VT
with
std::forward<Args>(args).... Postconditions:
*this contains a value
. Returns: A reference to the new contained value
. Throws: Any exception thrown by the selected constructor of
VT. Remarks: If an exception is thrown during the call to
VT's constructor,
*this does not contain a value, and any previously contained value
has been destroyed
. template<class T, class U, class... Args>
decay_t<T>& emplace(initializer_list<U> il, Args&&... args);
Constraints:
is_copy_constructible_v<VT> is
true and
is_constructible_v<VT, initializer_list<U>&, Args...> is
true. Then direct-non-list-initializes the contained value
of type
VT with
il, std::forward<Args>(args).... Postconditions:
*this contains a value
. Returns: A reference to the new contained value
. Throws: Any exception thrown by the selected constructor of
VT. Remarks: If an exception is thrown during the call to
VT's constructor,
*this does not contain a value, and any previously contained value
has been destroyed
. Effects: If
has_value() is
true, destroys the contained value
. Postconditions:
has_value() is
false. void swap(any& rhs) noexcept;
Effects: Exchanges the states of
*this and
rhs. bool has_value() const noexcept;
Returns:
true if
*this contains an object, otherwise
false. const type_info& type() const noexcept;
Returns:
typeid(T) if
*this has a contained value of type
T,
otherwise
typeid(void). [
Note 1:
Useful for querying against types known either at compile time or only at runtime
. —
end note]
void swap(any& x, any& y) noexcept;
Effects: Equivalent to
x.swap(y). template<class T, class... Args>
any make_any(Args&&... args);
Effects: Equivalent to: return any(in_place_type<T>, std::forward<Args>(args)...);
template<class T, class U, class... Args>
any make_any(initializer_list<U> il, Args&&... args);
Effects: Equivalent to: return any(in_place_type<T>, il, std::forward<Args>(args)...);
template<class T>
T any_cast(const any& operand);
template<class T>
T any_cast(any& operand);
template<class T>
T any_cast(any&& operand);
Let
U be the type
remove_cvref_t<T>.Mandates: For the first overload,
is_constructible_v<T, const U&> is
true. For the second overload,
is_constructible_v<T, U&> is
true. For the third overload,
is_constructible_v<T, U> is
true.Returns: For the first and second overload,
static_cast<T>(*any_cast<U>(&operand)). For the third overload,
static_cast<T>(std::move(*any_cast<U>(&operand))).Throws:
bad_any_cast if
operand.type() != typeid(remove_reference_t<T>). [
Example 1:
any x(5);
assert(any_cast<int>(x) == 5);
any_cast<int&>(x) = 10;
assert(any_cast<int>(x) == 10);
x = "Meow";
assert(strcmp(any_cast<const char*>(x), "Meow") == 0);
any_cast<const char*&>(x) = "Harry";
assert(strcmp(any_cast<const char*>(x), "Harry") == 0);
x = string("Meow");
string s, s2("Jane");
s = move(any_cast<string&>(x));
assert(s == "Meow");
any_cast<string&>(x) = move(s2);
assert(any_cast<const string&>(x) == "Jane");
string cat("Meow");
const any y(cat);
assert(any_cast<const string&>(y) == cat);
any_cast<string&>(y);
—
end example]
template<class T>
const T* any_cast(const any* operand) noexcept;
template<class T>
T* any_cast(any* operand) noexcept;
Mandates:
is_void_v<T> is
false. Returns: If
operand != nullptr && operand->type() == typeid(T) is
true,
a pointer to the object contained by
operand;
otherwise,
nullptr. [
Example 2:
bool is_string(const any& operand) {
return any_cast<string>(&operand) != nullptr;
}
—
end example]
Subclause
[expected] describes the class template
expected
that represents expected objects
. An
expected<T, E> object holds
an object of type
T or an object of type
E and
manages the lifetime of the contained objects
.
Subclause
[expected.unexpected] describes the class template
unexpected
that represents unexpected objects stored in
expected objects
.namespace std {
template<class E>
class unexpected {
public:
constexpr unexpected(const unexpected&) = default;
constexpr unexpected(unexpected&&) = default;
template<class Err = E>
constexpr explicit unexpected(Err&&);
template<class... Args>
constexpr explicit unexpected(in_place_t, Args&&...);
template<class U, class... Args>
constexpr explicit unexpected(in_place_t, initializer_list<U>, Args&&...);
constexpr unexpected& operator=(const unexpected&) = default;
constexpr unexpected& operator=(unexpected&&) = default;
constexpr const E& error() const & noexcept;
constexpr E& error() & noexcept;
constexpr const E&& error() const && noexcept;
constexpr E&& error() && noexcept;
constexpr void swap(unexpected& other) noexcept(see below);
template<class E2>
friend constexpr bool operator==(const unexpected&, const unexpected<E2>&);
friend constexpr void swap(unexpected& x, unexpected& y) noexcept(noexcept(x.swap(y)));
private:
E unex;
};
template<class E> unexpected(E) -> unexpected<E>;
}
A program that instantiates the definition of
unexpected for
a non-object type,
an array type,
a specialization of
unexpected, or
a cv-qualified type
is ill-formed
.template<class Err = E>
constexpr explicit unexpected(Err&& e);
Constraints:
- is_same_v<remove_cvref_t<Err>, unexpected> is false; and
- is_same_v<remove_cvref_t<Err>, in_place_t> is false; and
- is_constructible_v<E, Err> is true.
Effects: Direct-non-list-initializes
unex with
std::forward<Err>(e). Throws: Any exception thrown by the initialization of
unex. template<class... Args>
constexpr explicit unexpected(in_place_t, Args&&... args);
Constraints:
is_constructible_v<E, Args...> is
true. Effects: Direct-non-list-initializes
unex with
std::forward<Args>(args).... Throws: Any exception thrown by the initialization of
unex. template<class U, class... Args>
constexpr explicit unexpected(in_place_t, initializer_list<U> il, Args&&... args);
Constraints:
is_constructible_v<E, initializer_list<U>&, Args...> is
true. Effects: Direct-non-list-initializes
unex with
il, std::forward<Args>(args).... Throws: Any exception thrown by the initialization of
unex. constexpr const E& error() const & noexcept;
constexpr E& error() & noexcept;
constexpr E&& error() && noexcept;
constexpr const E&& error() const && noexcept;
Returns:
std::move(unex). constexpr void swap(unexpected& other) noexcept(is_nothrow_swappable_v<E>);
Mandates:
is_swappable_v<E> is
true. Effects: Equivalent to:
using std::swap; swap(unex, other.unex);
friend constexpr void swap(unexpected& x, unexpected& y) noexcept(noexcept(x.swap(y)));
Constraints:
is_swappable_v<E> is
true. Effects: Equivalent to
x.swap(y). template<class E2>
friend constexpr bool operator==(const unexpected& x, const unexpected<E2>& y);
Mandates: The expression
x.error() == y.error() is well-formed and
its result is convertible to
bool. Returns:
x.error() == y.error(). namespace std {
template<class E>
class bad_expected_access : public bad_expected_access<void> {
public:
constexpr explicit bad_expected_access(E);
constexpr const char* what() const noexcept override;
constexpr E& error() & noexcept;
constexpr const E& error() const & noexcept;
constexpr E&& error() && noexcept;
constexpr const E&& error() const && noexcept;
private:
E unex;
};
}
The class template
bad_expected_access
defines the type of objects thrown as exceptions to report the situation
where an attempt is made to access the value of an
expected<T, E> object
for which
has_value() is
false.constexpr explicit bad_expected_access(E e);
Effects: Initializes
unex with
std::move(e). constexpr const E& error() const & noexcept;
constexpr E& error() & noexcept;
constexpr E&& error() && noexcept;
constexpr const E&& error() const && noexcept;
Returns:
std::move(unex). constexpr const char* what() const noexcept override;
Returns: An
implementation-defined
ntbs,
which during constant evaluation is encoded with
the ordinary literal encoding (
[lex.ccon])
. namespace std {
template<>
class bad_expected_access<void> : public exception {
protected:
constexpr bad_expected_access() noexcept;
constexpr bad_expected_access(const bad_expected_access&) noexcept;
constexpr bad_expected_access(bad_expected_access&&) noexcept;
constexpr bad_expected_access& operator=(const bad_expected_access&) noexcept;
constexpr bad_expected_access& operator=(bad_expected_access&&) noexcept;
constexpr ~bad_expected_access();
public:
constexpr const char* what() const noexcept override;
};
}
constexpr const char* what() const noexcept override;
Returns: An
implementation-defined
ntbs,
which during constant evaluation is encoded with
the ordinary literal encoding (
[lex.ccon])
. namespace std {
template<class T, class E>
class expected {
public:
using value_type = T;
using error_type = E;
using unexpected_type = unexpected<E>;
template<class U>
using rebind = expected<U, error_type>;
constexpr expected();
constexpr expected(const expected&);
constexpr expected(expected&&) noexcept(see below);
template<class U, class G>
constexpr explicit(see below) expected(const expected<U, G>&);
template<class U, class G>
constexpr explicit(see below) expected(expected<U, G>&&);
template<class U = remove_cv_t<T>>
constexpr explicit(see below) expected(U&& v);
template<class G>
constexpr explicit(see below) expected(const unexpected<G>&);
template<class G>
constexpr explicit(see below) expected(unexpected<G>&&);
template<class... Args>
constexpr explicit expected(in_place_t, Args&&...);
template<class U, class... Args>
constexpr explicit expected(in_place_t, initializer_list<U>, Args&&...);
template<class... Args>
constexpr explicit expected(unexpect_t, Args&&...);
template<class U, class... Args>
constexpr explicit expected(unexpect_t, initializer_list<U>, Args&&...);
constexpr ~expected();
constexpr expected& operator=(const expected&);
constexpr expected& operator=(expected&&) noexcept(see below);
template<class U = remove_cv_t<T>> constexpr expected& operator=(U&&);
template<class G>
constexpr expected& operator=(const unexpected<G>&);
template<class G>
constexpr expected& operator=(unexpected<G>&&);
template<class... Args>
constexpr T& emplace(Args&&...) noexcept;
template<class U, class... Args>
constexpr T& emplace(initializer_list<U>, Args&&...) noexcept;
constexpr void swap(expected&) noexcept(see below);
friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(x.swap(y)));
constexpr const T* operator->() const noexcept;
constexpr T* operator->() noexcept;
constexpr const T& operator*() const & noexcept;
constexpr T& operator*() & noexcept;
constexpr const T&& operator*() const && noexcept;
constexpr T&& operator*() && noexcept;
constexpr explicit operator bool() const noexcept;
constexpr bool has_value() const noexcept;
constexpr bool has_error() const noexcept;
constexpr const T& value() const &;
constexpr T& value() &;
constexpr const T&& value() const &&;
constexpr T&& value() &&;
constexpr const E& error() const & noexcept;
constexpr E& error() & noexcept;
constexpr const E&& error() const && noexcept;
constexpr E&& error() && noexcept;
template<class U = remove_cv_t<T>> constexpr T value_or(U&&) const &;
template<class U = remove_cv_t<T>> constexpr T value_or(U&&) &&;
template<class G = E> constexpr E error_or(G&&) const &;
template<class G = E> constexpr E error_or(G&&) &&;
template<class F> constexpr auto and_then(F&& f) &;
template<class F> constexpr auto and_then(F&& f) &&;
template<class F> constexpr auto and_then(F&& f) const &;
template<class F> constexpr auto and_then(F&& f) const &&;
template<class F> constexpr auto or_else(F&& f) &;
template<class F> constexpr auto or_else(F&& f) &&;
template<class F> constexpr auto or_else(F&& f) const &;
template<class F> constexpr auto or_else(F&& f) const &&;
template<class F> constexpr auto transform(F&& f) &;
template<class F> constexpr auto transform(F&& f) &&;
template<class F> constexpr auto transform(F&& f) const &;
template<class F> constexpr auto transform(F&& f) const &&;
template<class F> constexpr auto transform_error(F&& f) &;
template<class F> constexpr auto transform_error(F&& f) &&;
template<class F> constexpr auto transform_error(F&& f) const &;
template<class F> constexpr auto transform_error(F&& f) const &&;
template<class T2, class E2> requires (!is_void_v<T2>)
friend constexpr bool operator==(const expected& x, const expected<T2, E2>& y);
template<class T2>
friend constexpr bool operator==(const expected&, const T2&);
template<class E2>
friend constexpr bool operator==(const expected&, const unexpected<E2>&);
private:
bool has_val;
union {
remove_cv_t<T> val;
E unex;
};
};
}
Any object of type
expected<T, E> either
contains a value of type
T or
a value of type
E
nested within (
[intro.object]) it
. Member
has_val indicates whether the
expected<T, E> object
contains an object of type
T.A type
T is a
valid value type for expected,
if
remove_cv_t<T> is
void
or a complete non-array object type that is not
in_place_t,
unexpect_t,
or a specialization of
unexpected. A program which instantiates class template
expected<T, E>
with an argument
T that is not a valid value
type for
expected is ill-formed
. A program that instantiates
the definition of the template
expected<T, E>
with a type for the
E parameter
that is not a valid template argument for
unexpected is ill-formed
.The exposition-only variable template
converts-from-any-cvref
defined in
[optional.ctor]
is used by some constructors for
expected.Constraints:
is_default_constructible_v<T> is
true. Effects: Value-initializes
val. Postconditions:
has_value() is
true. Throws: Any exception thrown by the initialization of
val. constexpr expected(const expected& rhs);
Effects: If
rhs.has_value() is
true,
direct-non-list-initializes
val with
*rhs. Otherwise, direct-non-list-initializes
unex with
rhs.error().Postconditions:
rhs.has_value() == this->has_value(). Throws: Any exception thrown by the initialization of
val or
unex. Remarks: This constructor is defined as deleted unless
- is_copy_constructible_v<T> is true and
- is_copy_constructible_v<E> is true.
This constructor is trivial if
- is_trivially_copy_constructible_v<T> is true and
- is_trivially_copy_constructible_v<E> is true.
constexpr expected(expected&& rhs) noexcept(see below);
Constraints:
- is_move_constructible_v<T> is true and
- is_move_constructible_v<E> is true.
Effects: If
rhs.has_value() is
true,
direct-non-list-initializes
val with
std::move(*rhs). Otherwise,
direct-non-list-initializes
unex with
std::move(rhs.error()).Postconditions:
rhs.has_value() is unchanged;
rhs.has_value() == this->has_value() is
true. Throws: Any exception thrown by the initialization of
val or
unex. Remarks: The exception specification is equivalent to
is_nothrow_move_constructible_v<T> &&
is_nothrow_move_constructible_v<E>. This constructor is trivial if
- is_trivially_move_constructible_v<T> is true and
- is_trivially_move_constructible_v<E> is true.
template<class U, class G>
constexpr explicit(see below) expected(const expected<U, G>& rhs);
template<class U, class G>
constexpr explicit(see below) expected(expected<U, G>&& rhs);
Let:
UF be
const U& for the first overload and
U for the second overload
. GF be
const G& for the first overload and
G for the second overload
.
Constraints:
- is_constructible_v<T, UF> is true; and
- is_constructible_v<E, GF> is true; and
- if T is not cv bool,
converts-from-any-cvref<T, expected<U, G>> is false; and
- is_constructible_v<unexpected<E>, expected<U, G>&> is false; and
- is_constructible_v<unexpected<E>, expected<U, G>> is false; and
- is_constructible_v<unexpected<E>, const expected<U, G>&> is false; and
- is_constructible_v<unexpected<E>, const expected<U, G>> is false.
Effects: If
rhs.has_value(),
direct-non-list-initializes
val with
std::forward<UF>(*rhs). Otherwise,
direct-non-list-initializes
unex with
std::forward<GF>(rhs.error()).Postconditions:
rhs.has_value() is unchanged;
rhs.has_value() == this->has_value() is
true. Throws: Any exception thrown by the initialization of
val or
unex. Remarks: The expression inside
explicit is equivalent to
!is_convertible_v<UF, T> || !is_convertible_v<GF, E>. template<class U = remove_cv_t<T>>
constexpr explicit(!is_convertible_v<U, T>) expected(U&& v);
Constraints:
- is_same_v<remove_cvref_t<U>, in_place_t> is false; and
- is_same_v<remove_cvref_t<U>, expected> is false; and
- is_same_v<remove_cvref_t<U>, unexpect_t> is false; and
- remove_cvref_t<U> is not a specialization of unexpected; and
- is_constructible_v<T, U> is true; and
- if T is cv bool,
remove_cvref_t<U> is not a specialization of expected.
Effects: Direct-non-list-initializes
val with
std::forward<U>(v). Postconditions:
has_value() is
true. Throws: Any exception thrown by the initialization of
val. template<class G>
constexpr explicit(!is_convertible_v<const G&, E>) expected(const unexpected<G>& e);
template<class G>
constexpr explicit(!is_convertible_v<G, E>) expected(unexpected<G>&& e);
Let
GF be
const G& for the first overload and
G for the second overload
.Constraints:
is_constructible_v<E, GF> is
true. Effects: Direct-non-list-initializes
unex with
std::forward<GF>(e.error()). Postconditions:
has_value() is
false. Throws: Any exception thrown by the initialization of
unex. template<class... Args>
constexpr explicit expected(in_place_t, Args&&... args);
Constraints:
is_constructible_v<T, Args...> is
true. Effects: Direct-non-list-initializes
val with
std::forward<Args>(args).... Postconditions:
has_value() is
true. Throws: Any exception thrown by the initialization of
val. template<class U, class... Args>
constexpr explicit expected(in_place_t, initializer_list<U> il, Args&&... args);
Constraints:
is_constructible_v<T, initializer_list<U>&, Args...> is
true. Effects: Direct-non-list-initializes
val with
il, std::forward<Args>(args).... Postconditions:
has_value() is
true. Throws: Any exception thrown by the initialization of
val. template<class... Args>
constexpr explicit expected(unexpect_t, Args&&... args);
Constraints:
is_constructible_v<E, Args...> is
true. Effects: Direct-non-list-initializes
unex with
std::forward<Args>(args).... Postconditions:
has_value() is
false. Throws: Any exception thrown by the initialization of
unex. template<class U, class... Args>
constexpr explicit expected(unexpect_t, initializer_list<U> il, Args&&... args);
Constraints:
is_constructible_v<E, initializer_list<U>&, Args...> is
true. Effects: Direct-non-list-initializes
unex with
il, std::forward<Args>(args).... Postconditions:
has_value() is
false. Throws: Any exception thrown by the initialization of
unex. Effects: If
has_value() is
true, destroys
val,
otherwise destroys
unex. Remarks: If
is_trivially_destructible_v<T> is
true, and
is_trivially_destructible_v<E> is
true,
then this destructor is a trivial destructor
. This subclause makes use of the following exposition-only function template:
template<class T, class U, class... Args>
constexpr void reinit-expected(T& newval, U& oldval, Args&&... args) {
if constexpr (is_nothrow_constructible_v<T, Args...>) {
destroy_at(addressof(oldval));
construct_at(addressof(newval), std::forward<Args>(args)...);
} else if constexpr (is_nothrow_move_constructible_v<T>) {
T tmp(std::forward<Args>(args)...);
destroy_at(addressof(oldval));
construct_at(addressof(newval), std::move(tmp));
} else {
U tmp(std::move(oldval));
destroy_at(addressof(oldval));
try {
construct_at(addressof(newval), std::forward<Args>(args)...);
} catch (...) {
construct_at(addressof(oldval), std::move(tmp));
throw;
}
}
}
constexpr expected& operator=(const expected& rhs);
Effects:
If
this->has_value() && rhs.has_value() is
true,
equivalent to
val = *rhs.Otherwise, if this->has_value() is true, equivalent to:
reinit-expected(unex, val, rhs.error())
Otherwise, if rhs.has_value() is true, equivalent to:
reinit-expected(val, unex, *rhs)
Otherwise, equivalent to
unex = rhs.error().
Then, if no exception was thrown,
equivalent to: has_val = rhs.has_value(); return *this;
Remarks: This operator is defined as deleted unless:
- is_copy_assignable_v<T> is true and
- is_copy_constructible_v<T> is true and
- is_copy_assignable_v<E> is true and
- is_copy_constructible_v<E> is true and
- is_nothrow_move_constructible_v<T> || is_nothrow_move_constructible_v<E>
is true.
This operator is trivial if:
- is_trivially_copy_constructible_v<T> is true, and
- is_trivially_copy_assignable_v<T> is true, and
- is_trivially_destructible_v<T> is true, and
- is_trivially_copy_constructible_v<E> is true, and
- is_trivially_copy_assignable_v<E> is true, and
- is_trivially_destructible_v<E> is true.
constexpr expected& operator=(expected&& rhs) noexcept(see below);
Constraints:
- is_move_constructible_v<T> is true and
- is_move_assignable_v<T> is true and
- is_move_constructible_v<E> is true and
- is_move_assignable_v<E> is true and
- is_nothrow_move_constructible_v<T> || is_nothrow_move_constructible_v<E>
is true.
Effects:
If
this->has_value() && rhs.has_value() is
true,
equivalent to
val = std::move(*rhs).Otherwise, if this->has_value() is true, equivalent to:
reinit-expected(unex, val, std::move(rhs.error()))
Otherwise, if rhs.has_value() is true, equivalent to:
reinit-expected(val, unex, std::move(*rhs))
Otherwise, equivalent to
unex = std::move(rhs.error()).
Then, if no exception was thrown,
equivalent to: has_val = rhs.has_value(); return *this;
Remarks: The exception specification is equivalent to:
is_nothrow_move_assignable_v<T> && is_nothrow_move_constructible_v<T> &&
is_nothrow_move_assignable_v<E> && is_nothrow_move_constructible_v<E>
This operator is trivial if:
- is_trivially_move_constructible_v<T> is true, and
- is_trivially_move_assignable_v<T> is true, and
- is_trivially_destructible_v<T> is true, and
- is_trivially_move_constructible_v<E> is true, and
- is_trivially_move_assignable_v<E> is true, and
- is_trivially_destructible_v<E> is true.
template<class U = remove_cv_t<T>>
constexpr expected& operator=(U&& v);
Constraints:
- is_same_v<expected, remove_cvref_t<U>> is false; and
- remove_cvref_t<U> is not a specialization of unexpected; and
- is_constructible_v<T, U> is true; and
- is_assignable_v<T&, U> is true; and
- is_nothrow_constructible_v<T, U> || is_nothrow_move_constructible_v<T> ||
is_nothrow_move_constructible_v<E>
is true.
Effects:
- If has_value() is true,
equivalent to: val = std::forward<U>(v);
- Otherwise, equivalent to:
reinit-expected(val, unex, std::forward<U>(v));
has_val = true;
template<class G>
constexpr expected& operator=(const unexpected<G>& e);
template<class G>
constexpr expected& operator=(unexpected<G>&& e);
Let
GF be
const G& for the first overload and
G for the second overload
.Constraints:
- is_constructible_v<E, GF> is true; and
- is_assignable_v<E&, GF> is true; and
- is_nothrow_constructible_v<E, GF> || is_nothrow_move_constructible_v<T> ||
is_nothrow_move_constructible_v<E> is true.
Effects:
- If has_value() is true, equivalent to:
reinit-expected(unex, val, std::forward<GF>(e.error()));
has_val = false;
- Otherwise, equivalent to:
unex = std::forward<GF>(e.error());
template<class... Args>
constexpr T& emplace(Args&&... args) noexcept;
Constraints:
is_nothrow_constructible_v<T, Args...> is
true. Effects: Equivalent to:
if (has_value()) {
destroy_at(addressof(val));
} else {
destroy_at(addressof(unex));
has_val = true;
}
return *construct_at(addressof(val), std::forward<Args>(args)...);
template<class U, class... Args>
constexpr T& emplace(initializer_list<U> il, Args&&... args) noexcept;
Constraints:
is_nothrow_constructible_v<T, initializer_list<U>&, Args...>
is
true. Effects: Equivalent to:
if (has_value()) {
destroy_at(addressof(val));
} else {
destroy_at(addressof(unex));
has_val = true;
}
return *construct_at(addressof(val), il, std::forward<Args>(args)...);
constexpr void swap(expected& rhs) noexcept(see below);
Constraints:
- is_swappable_v<T> is true and
- is_swappable_v<E> is true and
- is_move_constructible_v<T> && is_move_constructible_v<E>
is true, and
- is_nothrow_move_constructible_v<T> || is_nothrow_move_constructible_v<E>
is true.
Effects: See Table Clause
72. Table
72 —
swap(expected&) effects
[tab:expected.object.swap] | | |
| equivalent to: using std::swap; swap(val, rhs.val); | |
| | equivalent to: using std::swap; swap(unex, rhs.unex); |
For the case where rhs.has_value() is false and
this->has_value() is true, equivalent to:
if constexpr (is_nothrow_move_constructible_v<E>) {
E tmp(std::move(rhs.unex));
destroy_at(addressof(rhs.unex));
try {
construct_at(addressof(rhs.val), std::move(val));
destroy_at(addressof(val));
construct_at(addressof(unex), std::move(tmp));
} catch(...) {
construct_at(addressof(rhs.unex), std::move(tmp));
throw;
}
} else {
remove_cv_t<T> tmp(std::move(val));
destroy_at(addressof(val));
try {
construct_at(addressof(unex), std::move(rhs.unex));
destroy_at(addressof(rhs.unex));
construct_at(addressof(rhs.val), std::move(tmp));
} catch (...) {
construct_at(addressof(val), std::move(tmp));
throw;
}
}
has_val = false;
rhs.has_val = true;
Throws: Any exception thrown by the expressions in the
Effects. Remarks: The exception specification is equivalent to:
is_nothrow_move_constructible_v<T> && is_nothrow_swappable_v<T> &&
is_nothrow_move_constructible_v<E> && is_nothrow_swappable_v<E>
friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(x.swap(y)));
Effects: Equivalent to
x.swap(y). constexpr const T* operator->() const noexcept;
constexpr T* operator->() noexcept;
Hardened preconditions:
has_value() is
true. constexpr const T& operator*() const & noexcept;
constexpr T& operator*() & noexcept;
Hardened preconditions:
has_value() is
true. constexpr T&& operator*() && noexcept;
constexpr const T&& operator*() const && noexcept;
Hardened preconditions:
has_value() is
true. Returns:
std::move(val). constexpr explicit operator bool() const noexcept;
constexpr bool has_value() const noexcept;
constexpr bool has_error() const noexcept;
Effects: Equivalent to:
return !has_value();
constexpr const T& value() const &;
constexpr T& value() &;
Mandates:
is_copy_constructible_v<E> is
true. Returns:
val, if
has_value() is
true. Throws:
bad_expected_access(as_const(error())) if
has_value() is
false. constexpr T&& value() &&;
constexpr const T&& value() const &&;
Mandates:
is_copy_constructible_v<E> is
true and
is_constructible_v<E, decltype(std::move(error()))> is
true. Returns:
std::move(val), if
has_value() is
true. Throws:
bad_expected_access(std::move(error()))
if
has_value() is
false. constexpr const E& error() const & noexcept;
constexpr E& error() & noexcept;
Hardened preconditions:
has_value() is
false. constexpr E&& error() && noexcept;
constexpr const E&& error() const && noexcept;
Hardened preconditions:
has_value() is
false. Returns:
std::move(unex). template<class U = remove_cv_t<T>> constexpr T value_or(U&& v) const &;
Mandates:
is_copy_constructible_v<T> is
true and
is_convertible_v<U, T> is
true. Returns:
has_value() ? **this : static_cast<T>(std::forward<U>(v)). template<class U = remove_cv_t<T>> constexpr T value_or(U&& v) &&;
Mandates:
is_move_constructible_v<T> is
true and
is_convertible_v<U, T> is
true. Returns:
has_value() ? std::move(**this) : static_cast<T>(std::forward<U>(v)). template<class G = E> constexpr E error_or(G&& e) const &;
Mandates:
is_copy_constructible_v<E> is
true and
is_convertible_v<G, E> is
true. Returns:
std::forward<G>(e) if
has_value() is
true,
error() otherwise
. template<class G = E> constexpr E error_or(G&& e) &&;
Mandates:
is_move_constructible_v<E> is
true and
is_convertible_v<G, E> is
true. Returns:
std::forward<G>(e) if
has_value() is
true,
std::move(error()) otherwise
. template<class F> constexpr auto and_then(F&& f) &;
template<class F> constexpr auto and_then(F&& f) const &;
Let
U be
remove_cvref_t<invoke_result_t<F, decltype((val))>>.Constraints:
is_constructible_v<E, decltype(error())> is
true. Mandates:
U is a specialization of
expected and
is_same_v<typename U::error_type, E> is
true. Effects: Equivalent to:
if (has_value())
return invoke(std::forward<F>(f), val);
else
return U(unexpect, error());
template<class F> constexpr auto and_then(F&& f) &&;
template<class F> constexpr auto and_then(F&& f) const &&;
Let
U be
remove_cvref_t<invoke_result_t<F, decltype(std::move(val))>>.Constraints:
is_constructible_v<E, decltype(std::move(error()))> is
true. Mandates:
U is a specialization of
expected and
is_same_v<typename U::error_type, E> is
true. Effects: Equivalent to:
if (has_value())
return invoke(std::forward<F>(f), std::move(val));
else
return U(unexpect, std::move(error()));
template<class F> constexpr auto or_else(F&& f) &;
template<class F> constexpr auto or_else(F&& f) const &;
Let
G be
remove_cvref_t<invoke_result_t<F, decltype(error())>>.Constraints:
is_constructible_v<T, decltype((val))> is
true. Mandates:
G is a specialization of
expected and
is_same_v<typename G::value_type, T> is
true. Effects: Equivalent to:
if (has_value())
return G(in_place, val);
else
return invoke(std::forward<F>(f), error());
template<class F> constexpr auto or_else(F&& f) &&;
template<class F> constexpr auto or_else(F&& f) const &&;
Let
G be
remove_cvref_t<invoke_result_t<F, decltype(std::move(error()))>>.Constraints:
is_constructible_v<T, decltype(std::move(val))> is
true. Mandates:
G is a specialization of
expected and
is_same_v<typename G::value_type, T> is
true. Effects: Equivalent to:
if (has_value())
return G(in_place, std::move(val));
else
return invoke(std::forward<F>(f), std::move(error()));
Let
U be
remove_cv_t<invoke_result_t<F, decltype((val))>>.Constraints:
is_constructible_v<E, decltype(error())> is
true. Mandates:
U is a valid value type for
expected. If
is_void_v<U> is
false,
the declaration
U u(invoke(std::forward<F>(f), val));
is well-formed
.Effects:
If
has_value() is
false, returns
expected<U, E>(unexpect, error()).Otherwise, if
is_void_v<U> is
false, returns an
expected<U, E> object whose
has_val member is
true
and
val member is direct-non-list-initialized with
invoke(std::forward<F>(f), val).Otherwise, evaluates
invoke(std::forward<F>(f), val) and then
returns
expected<U, E>().
Let
U be
remove_cv_t<invoke_result_t<F, decltype(std::move(val))>>.Constraints:
is_constructible_v<E, decltype(std::move(error()))> is
true. Mandates:
U is a valid value type for
expected. If
is_void_v<U> is
false, the declaration
U u(invoke(std::forward<F>(f), std::move(val)));
is well-formed
.Effects:
If
has_value() is
false, returns
expected<U, E>(unexpect, std::move(error())).Otherwise, if
is_void_v<U> is
false, returns an
expected<U, E> object whose
has_val member is
true
and
val member is direct-non-list-initialized with
invoke(std::forward<F>(f), std::move(val)).Otherwise, evaluates
invoke(std::forward<F>(f), std::move(val)) and
then returns
expected<U, E>().
Let
G be
remove_cv_t<invoke_result_t<F, decltype(error())>>.Constraints:
is_constructible_v<T, decltype((val))> is
true. Mandates:
G is a valid template argument
for
unexpected (
[expected.un.general]) and the declaration
G g(invoke(std::forward<F>(f), error()));
is well-formed
. Returns: If
has_value() is
true,
expected<T, G>(in_place, val); otherwise, an
expected<T, G>
object whose
has_val member is
false and
unex member
is direct-non-list-initialized with
invoke(std::forward<F>(f), error()). Let
G be
remove_cv_t<invoke_result_t<F, decltype(std::move(error()))>>.Constraints:
is_constructible_v<T, decltype(std::move(val))> is
true. Mandates:
G is a valid template argument
for
unexpected (
[expected.un.general]) and the declaration
G g(invoke(std::forward<F>(f), std::move(error())));
is well-formed
. Returns: If
has_value() is
true,
expected<T, G>(in_place, std::move(val)); otherwise, an
expected<T, G> object whose
has_val member is
false
and
unex member is direct-non-list-initialized with
invoke(std::forward<F>(f), std::move(error())). template<class T2, class E2> requires (!is_void_v<T2>)
friend constexpr bool operator==(const expected& x, const expected<T2, E2>& y);
Constraints: The expressions
*x == *y and
x.error() == y.error()
are well-formed and their results are convertible to
bool. Returns: If
x.has_value() does not equal
y.has_value(),
false;
otherwise if
x.has_value() is
true,
*x == *y;
otherwise
x.error() == y.error(). template<class T2> friend constexpr bool operator==(const expected& x, const T2& v);
Constraints:
T2 is not a specialization of
expected. The expression
*x == v is well-formed and
its result is convertible to
bool. Returns: If
x.has_value() is
true,
*x == v;
otherwise
false. template<class E2> friend constexpr bool operator==(const expected& x, const unexpected<E2>& e);
Constraints: The expression
x.error() == e.error() is well-formed and
its result is convertible to
bool. Returns: If
!x.has_value() is
true,
x.error() == e.error();
otherwise
false. namespace std {
template<class T, class E> requires is_void_v<T>
class expected<T, E> {
public:
using value_type = T;
using error_type = E;
using unexpected_type = unexpected<E>;
template<class U>
using rebind = expected<U, error_type>;
constexpr expected() noexcept;
constexpr expected(const expected&);
constexpr expected(expected&&) noexcept(see below);
template<class U, class G>
constexpr explicit(see below) expected(const expected<U, G>&);
template<class U, class G>
constexpr explicit(see below) expected(expected<U, G>&&);
template<class G>
constexpr explicit(see below) expected(const unexpected<G>&);
template<class G>
constexpr explicit(see below) expected(unexpected<G>&&);
constexpr explicit expected(in_place_t) noexcept;
template<class... Args>
constexpr explicit expected(unexpect_t, Args&&...);
template<class U, class... Args>
constexpr explicit expected(unexpect_t, initializer_list<U>, Args&&...);
constexpr ~expected();
constexpr expected& operator=(const expected&);
constexpr expected& operator=(expected&&) noexcept(see below);
template<class G>
constexpr expected& operator=(const unexpected<G>&);
template<class G>
constexpr expected& operator=(unexpected<G>&&);
constexpr void emplace() noexcept;
constexpr void swap(expected&) noexcept(see below);
friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(x.swap(y)));
constexpr explicit operator bool() const noexcept;
constexpr bool has_value() const noexcept;
constexpr bool has_error() const noexcept;
constexpr void operator*() const noexcept;
constexpr void value() const &;
constexpr void value() &&;
constexpr const E& error() const & noexcept;
constexpr E& error() & noexcept;
constexpr const E&& error() const && noexcept;
constexpr E&& error() && noexcept;
template<class G = E> constexpr E error_or(G&&) const &;
template<class G = E> constexpr E error_or(G&&) &&;
template<class F> constexpr auto and_then(F&& f) &;
template<class F> constexpr auto and_then(F&& f) &&;
template<class F> constexpr auto and_then(F&& f) const &;
template<class F> constexpr auto and_then(F&& f) const &&;
template<class F> constexpr auto or_else(F&& f) &;
template<class F> constexpr auto or_else(F&& f) &&;
template<class F> constexpr auto or_else(F&& f) const &;
template<class F> constexpr auto or_else(F&& f) const &&;
template<class F> constexpr auto transform(F&& f) &;
template<class F> constexpr auto transform(F&& f) &&;
template<class F> constexpr auto transform(F&& f) const &;
template<class F> constexpr auto transform(F&& f) const &&;
template<class F> constexpr auto transform_error(F&& f) &;
template<class F> constexpr auto transform_error(F&& f) &&;
template<class F> constexpr auto transform_error(F&& f) const &;
template<class F> constexpr auto transform_error(F&& f) const &&;
template<class T2, class E2> requires is_void_v<T2>
friend constexpr bool operator==(const expected& x, const expected<T2, E2>& y);
template<class E2>
friend constexpr bool operator==(const expected&, const unexpected<E2>&);
private:
bool has_val;
union {
E unex;
};
};
}
Any object of type
expected<T, E> either
represents a value of type
T, or
contains a value of type
E
nested within (
[intro.object]) it
. Member
has_val indicates whether the
expected<T, E> object
represents a value of type
T.A program that instantiates
the definition of the template
expected<T, E> with
a type for the
E parameter that
is not a valid template argument for
unexpected is ill-formed
.constexpr expected() noexcept;
Postconditions:
has_value() is
true. constexpr expected(const expected& rhs);
Effects: If
rhs.has_value() is
false,
direct-non-list-initializes
unex with
rhs.error(). Postconditions:
rhs.has_value() == this->has_value(). Throws: Any exception thrown by the initialization of
unex. Remarks: This constructor is defined as deleted
unless
is_copy_constructible_v<E> is
true. This constructor is trivial
if
is_trivially_copy_constructible_v<E> is
true.constexpr expected(expected&& rhs) noexcept(is_nothrow_move_constructible_v<E>);
Constraints:
is_move_constructible_v<E> is
true. Effects: If
rhs.has_value() is
false,
direct-non-list-initializes
unex with
std::move(rhs.error()). Postconditions:
rhs.has_value() is unchanged;
rhs.has_value() == this->has_value() is
true. Throws: Any exception thrown by the initialization of
unex. Remarks: This constructor is trivial
if
is_trivially_move_constructible_v<E> is
true. template<class U, class G>
constexpr explicit(!is_convertible_v<const G&, E>) expected(const expected<U, G>& rhs);
template<class U, class G>
constexpr explicit(!is_convertible_v<G, E>) expected(expected<U, G>&& rhs);
Let
GF be
const G& for the first overload and
G for the second overload
.Constraints:
- is_void_v<U> is true; and
- is_constructible_v<E, GF> is true; and
- is_constructible_v<unexpected<E>, expected<U, G>&>
is false; and
- is_constructible_v<unexpected<E>, expected<U, G>>
is false; and
- is_constructible_v<unexpected<E>, const expected<U, G>&>
is false; and
- is_constructible_v<unexpected<E>, const expected<U, G>>
is false.
Effects: If
rhs.has_value() is
false,
direct-non-list-initializes
unex
with
std::forward<GF>(rhs.error()). Postconditions:
rhs.has_value() is unchanged;
rhs.has_value() == this->has_value() is
true. Throws: Any exception thrown by the initialization of
unex. template<class G>
constexpr explicit(!is_convertible_v<const G&, E>) expected(const unexpected<G>& e);
template<class G>
constexpr explicit(!is_convertible_v<G, E>) expected(unexpected<G>&& e);
Let
GF be
const G& for the first overload and
G for the second overload
.Constraints:
is_constructible_v<E, GF> is
true. Effects: Direct-non-list-initializes
unex
with
std::forward<GF>(e.error()). Postconditions:
has_value() is
false. Throws: Any exception thrown by the initialization of
unex. constexpr explicit expected(in_place_t) noexcept;
Postconditions:
has_value() is
true. template<class... Args>
constexpr explicit expected(unexpect_t, Args&&... args);
Constraints:
is_constructible_v<E, Args...> is
true. Effects: Direct-non-list-initializes
unex
with
std::forward<Args>(args).... Postconditions:
has_value() is
false. Throws: Any exception thrown by the initialization of
unex. template<class U, class... Args>
constexpr explicit expected(unexpect_t, initializer_list<U> il, Args&&... args);
Constraints:
is_constructible_v<E, initializer_list<U>&, Args...> is
true. Effects: Direct-non-list-initializes
unex
with
il, std::forward<Args>(args).... Postconditions:
has_value() is
false. Throws: Any exception thrown by the initialization of
unex. Effects: If
has_value() is
false, destroys
unex. Remarks: If
is_trivially_destructible_v<E> is
true,
then this destructor is a trivial destructor
. constexpr expected& operator=(const expected& rhs);
Effects:
If
this->has_value() && rhs.has_value() is
true, no effects
.Otherwise, if this->has_value() is true,
equivalent to: construct_at(addressof(unex), rhs.unex); has_val = false;
Otherwise, if
rhs.has_value() is
true,
destroys
unex and sets
has_val to
true.Otherwise, equivalent to
unex = rhs.error().
Remarks: This operator is defined as deleted unless
is_copy_assignable_v<E> is
true and
is_copy_constructible_v<E> is
true. This operator is trivial if
is_trivially_copy_constructible_v<E>,
is_trivially_copy_assignable_v<E>, and
is_trivially_destructible_v<E>
are all
true.constexpr expected& operator=(expected&& rhs) noexcept(see below);
Constraints:
is_move_constructible_v<E> is
true and
is_move_assignable_v<E> is
true. Effects:
If
this->has_value() && rhs.has_value() is
true, no effects
.Otherwise, if this->has_value() is true, equivalent to:
construct_at(addressof(unex), std::move(rhs.unex));
has_val = false;
Otherwise, if
rhs.has_value() is
true,
destroys
unex and sets
has_val to
true.Otherwise, equivalent to
unex = std::move(rhs.error()).
Remarks: The exception specification is equivalent to
is_nothrow_move_constructible_v<E> && is_nothrow_move_assignable_v<E>. This operator is trivial if
is_trivially_move_constructible_v<E>,
is_trivially_move_assignable_v<E>, and
is_trivially_destructible_v<E>
are all
true.template<class G>
constexpr expected& operator=(const unexpected<G>& e);
template<class G>
constexpr expected& operator=(unexpected<G>&& e);
Let
GF be
const G& for the first overload and
G for the second overload
.Constraints:
is_constructible_v<E, GF> is
true and
is_assignable_v<E&, GF> is
true. Effects:
- If has_value() is true, equivalent to:
construct_at(addressof(unex), std::forward<GF>(e.error()));
has_val = false;
- Otherwise, equivalent to:
unex = std::forward<GF>(e.error());
constexpr void emplace() noexcept;
Effects: If
has_value() is
false,
destroys
unex and sets
has_val to
true. constexpr void swap(expected& rhs) noexcept(see below);
Constraints:
is_swappable_v<E> is
true and
is_move_constructible_v<E> is
true. Effects: See Table Clause
73. For the case where rhs.has_value() is false and
this->has_value() is true, equivalent to:
construct_at(addressof(unex), std::move(rhs.unex));
destroy_at(addressof(rhs.unex));
has_val = false;
rhs.has_val = true;
Throws: Any exception thrown by the expressions in the
Effects. Remarks: The exception specification is equivalent to
is_nothrow_move_constructible_v<E> && is_nothrow_swappable_v<E>. friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(x.swap(y)));
Effects: Equivalent to
x.swap(y). constexpr explicit operator bool() const noexcept;
constexpr bool has_value() const noexcept;
constexpr bool has_error() const noexcept;
Effects: Equivalent to:
return !has_value();
constexpr void operator*() const noexcept;
Hardened preconditions:
has_value() is
true. constexpr void value() const &;
Mandates:
is_copy_constructible_v<E> is
true. Throws:
bad_expected_access(error()) if
has_value() is
false. constexpr void value() &&;
Mandates:
is_copy_constructible_v<E> is
true and
is_move_constructible_v<E> is
true. Throws:
bad_expected_access(std::move(error()))
if
has_value() is
false. constexpr const E& error() const & noexcept;
constexpr E& error() & noexcept;
Hardened preconditions:
has_value() is
false. constexpr E&& error() && noexcept;
constexpr const E&& error() const && noexcept;
Hardened preconditions:
has_value() is
false. Returns:
std::move(unex). template<class G = E> constexpr E error_or(G&& e) const &;
Mandates:
is_copy_constructible_v<E> is
true and
is_convertible_v<G, E> is
true. Returns:
std::forward<G>(e) if
has_value() is
true,
error() otherwise
. template<class G = E> constexpr E error_or(G&& e) &&;
Mandates:
is_move_constructible_v<E> is
true and
is_convertible_v<G, E> is
true. Returns:
std::forward<G>(e) if
has_value() is
true,
std::move(error()) otherwise
. template<class F> constexpr auto and_then(F&& f) &;
template<class F> constexpr auto and_then(F&& f) const &;
Let
U be
remove_cvref_t<invoke_result_t<F>>.Constraints:
is_constructible_v<E, decltype(error())>> is
true. Mandates:
U is a specialization of
expected and
is_same_v<typename U::error_type, E> is
true. Effects: Equivalent to:
if (has_value())
return invoke(std::forward<F>(f));
else
return U(unexpect, error());
template<class F> constexpr auto and_then(F&& f) &&;
template<class F> constexpr auto and_then(F&& f) const &&;
Let
U be
remove_cvref_t<invoke_result_t<F>>.Constraints:
is_constructible_v<E, decltype(std::move(error()))> is
true. Mandates:
U is a specialization of
expected and
is_same_v<typename U::error_type, E> is
true. Effects: Equivalent to:
if (has_value())
return invoke(std::forward<F>(f));
else
return U(unexpect, std::move(error()));
template<class F> constexpr auto or_else(F&& f) &;
template<class F> constexpr auto or_else(F&& f) const &;
Let
G be
remove_cvref_t<invoke_result_t<F, decltype(error())>>.Mandates:
G is a specialization of
expected and
is_same_v<typename G::value_type, T> is
true. Effects: Equivalent to:
if (has_value())
return G();
else
return invoke(std::forward<F>(f), error());
template<class F> constexpr auto or_else(F&& f) &&;
template<class F> constexpr auto or_else(F&& f) const &&;
Let
G be
remove_cvref_t<invoke_result_t<F, decltype(std::move(error()))>>.Mandates:
G is a specialization of
expected and
is_same_v<typename G::value_type, T> is
true. Effects: Equivalent to:
if (has_value())
return G();
else
return invoke(std::forward<F>(f), std::move(error()));
Let
U be
remove_cv_t<invoke_result_t<F>>.Constraints:
is_constructible_v<E, decltype(error())> is
true.