From 91fa7b0815291efe8c1a3830e65e8bc3f77b38a8 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Tue, 8 Feb 2022 22:36:18 +0100 Subject: [PATCH 1/2] P0323R12 std::expected - Introduce "General" subclauses to avoid hanging paragraphs. - Introduce "Returns: *this" to avoid duplication. - Add missing "friend" from item description of expected::operator==. --- source/lib-intro.tex | 1 - source/support.tex | 1 + source/utilities.tex | 2037 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 2038 insertions(+), 1 deletion(-) diff --git a/source/lib-intro.tex b/source/lib-intro.tex index 8b91715a40..a4e4fe6889 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -2480,7 +2480,6 @@ \item \indexlibraryzombie{uncaught_exception} \tcode{uncaught_exception}, \item \indexlibraryzombie{undeclare_no_pointers} \tcode{undeclare_no_pointers}, \item \indexlibraryzombie{undeclare_reachable} \tcode{undeclare_reachable}, -\item \indexlibraryzombie{unexpected} \tcode{unexpected}, and \item \indexlibraryzombie{unexpected_handler} \tcode{unexpected_handler}. \end{itemize} diff --git a/source/support.tex b/source/support.tex index a86e05dfb9..e8ccd20800 100644 --- a/source/support.tex +++ b/source/support.tex @@ -610,6 +610,7 @@ // \libheader{unordered_set} #define @\defnlibxname{cpp_lib_exchange_function}@ 201304L // also in \libheader{utility} #define @\defnlibxname{cpp_lib_execution}@ 201902L // also in \libheader{execution} +#define @\defnlibxname{cpp_lib_expected}@ 202202L // also in \libheader{expected} #define @\defnlibxname{cpp_lib_filesystem}@ 201703L // also in \libheader{filesystem} #define @\defnlibxname{cpp_lib_format}@ 202110L // also in \libheader{format} #define @\defnlibxname{cpp_lib_gcd_lcm}@ 201606L // also in \libheader{numeric} diff --git a/source/utilities.tex b/source/utilities.tex index 60f0e94e61..6308313a8b 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -16,6 +16,7 @@ \ref{optional} & Optional objects & \tcode{} \\ \rowsep \ref{variant} & Variants & \tcode{} \\ \rowsep \ref{any} & Storage for any type & \tcode{} \\ \rowsep +\ref{expected} & Expected objects & \tcode{} \\ \rowsep \ref{bitset} & Fixed-size sequences of bits & \tcode{} \\ \rowsep \ref{memory} & Memory & \tcode{}, \tcode{} \\ \rowsep \ref{smartptr} & Smart pointers & \tcode{} \\ \rowsep @@ -6463,6 +6464,2042 @@ \end{example} \end{itemdescr} +\rSec1[expected]{Expected objects} +\indexlibraryglobal{expected}% + +\rSec2[expected.general]{In general} + +\pnum +This subclause describes the class template \tcode{expected} +that represents expected objects. +An \tcode{expected} object holds +an object of type \tcode{T} or an object of type \tcode{unexpected} and +manages the lifetime of the contained objects. + +\rSec2[expected.syn]{Header \tcode{} synopsis} + +\indexlibraryglobal{unexpect_t}% +\indexlibraryglobal{unexpect}% +\begin{codeblock} +namespace std { + // \ref{expected.un.object}, class template \tcode{unexpected} + template class unexpected; + + // \ref{expected.bad}, class \tcode{bad_expected_access} + template class bad_expected_access; + + // \ref{expected.bad.void}, specialization for \tcode{void} + template<> class bad_expected_access; + + // in-place construction of unexpected values + struct unexpect_t { + explicit unexpect_t() = default; + }; + inline constexpr unexpect_t unexpect{}; + + // \ref{expected.expected}, class template \tcode{expected} + template class expected; + + // \ref{expected.void}, partial specialization of \tcode{expected} for \tcode{void} types + template requires is_void_v class expected; +} +\end{codeblock} + +\rSec2[expected.unexpected]{Unexpected objects} + +\rSec3[expected.un.general]{General} + +\pnum +This subclause describes the class template \tcode{unexpected} +that represents unexpected objects stored in \tcode{expected} objects. + +\rSec3[expected.un.object]{Class template \tcode{unexpected}} + +\rSec4[expected.un.object.general]{General} + +\indexlibraryglobal{unexpected}% +\begin{codeblock} +namespace std { + template + class unexpected { + public: + constexpr unexpected(const unexpected&) = default; + constexpr unexpected(unexpected&&) = default; + template + constexpr explicit unexpected(in_place_t, Args&&...); + template + constexpr explicit unexpected(in_place_t, initializer_list, Args&&...); + template + constexpr explicit unexpected(Err&&); + + constexpr unexpected& operator=(const unexpected&) = default; + constexpr unexpected& operator=(unexpected&&) = default; + + constexpr const E& value() const& noexcept; + constexpr E& value() & noexcept; + constexpr const E&& value() const&& noexcept; + constexpr E&& value() && noexcept; + + constexpr void swap(unexpected& other) noexcept(@\seebelow@); + + template + friend constexpr bool operator==(const unexpected&, const unexpected&); + + friend constexpr void swap(unexpected& x, unexpected& y) noexcept(noexcept(x.swap(y))); + + private: + E @\exposid{val}@; // \expos + }; + + template unexpected(E) -> unexpected; +} +\end{codeblock} + +\pnum +A program that instantiates the definition of \tcode{unexpected} for +a non-object type, +an array type, +a specialization of \tcode{unexpected}, or +a cv-qualified type +is ill-formed. + +\rSec4[expected.un.ctor]{Constructors} + +\indexlibraryctor{unexpected}% +\begin{itemdecl} +template + constexpr explicit unexpected(Err&& e); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_same_v, unexpected>} is \tcode{false}; and +\item +\tcode{is_same_v, in_place_t>} is \tcode{false}; and +\item +\tcode{is_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Direct-non-list-initializes \exposid{val} with \tcode{std::forward(e)}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{val}. +\end{itemdescr} + +\indexlibraryctor{unexpected}% +\begin{itemdecl} +template + constexpr explicit unexpected(in_place_t, Args&&...); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\effects +Direct-non-list-initializes +\exposid{val} with \tcode{std::forward(args)...}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{val}. +\end{itemdescr} + +\indexlibraryctor{unexpected}% +\begin{itemdecl} +template + constexpr explicit unexpected(in_place_t, initializer_list, Args&&...); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v\&, Args...>} is \tcode{true}. + +\pnum +\effects +Direct-non-list-initializes +\exposid{val} with \tcode{std::forward(args)...}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{val}. +\end{itemdescr} + +\rSec4[expected.un.obs]{Observers} + +\indexlibrarymember{value}{unexpected}% +\begin{itemdecl} +constexpr const E& value() const& noexcept; +constexpr E& value() & noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\exposid{val}. +\end{itemdescr} + +\indexlibrarymember{value}{unexpected}% +\begin{itemdecl} +constexpr E&& value() && noexcept; +constexpr const E&& value() const&& noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{std::move(\exposid{val})}. +\end{itemdescr} + +\rSec4[expected.un.swap]{Swap} + +\indexlibrarymember{swap}{unexpected}% +\begin{itemdecl} +constexpr void swap(unexpected& other) noexcept(is_nothrow_swappable_v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{is_swappable_v} is \tcode{true}. + +\pnum +\effects +Equivalent to: +\tcode{using std::swap; swap(\exposid{val}, other.\exposid{val});} +\end{itemdescr} + +\begin{itemdecl} +friend constexpr void swap(unexpected& x, unexpected& y) noexcept(noexcept(x.swap(y))); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_swappable_v} is \tcode{true}. + +\pnum +\effects +Equivalent to \tcode{x.swap(y)}. +\end{itemdescr} + +\rSec4[expected.un.eq]{Equality operator} + +\indexlibrarymember{operator==}{unexpected}% +\begin{itemdecl} +template + friend constexpr bool operator==(const unexpected& x, const unexpected& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +The expression \tcode{x.value() == y.value()} is well-formed and +its result is convertible to \tcode{bool}. + +\pnum +\returns +\tcode{x.value() == y.value()}. +\end{itemdescr} + +\rSec2[expected.bad]{Class template \tcode{bad_expected_access}} + +\indexlibraryglobal{bad_expected_access}% +\begin{codeblock} +namespace std { + template + class bad_expected_access : public bad_expected_access { + public: + explicit bad_expected_access(E); + const char* what() const noexcept override; + E& error() & noexcept; + const E& error() const& noexcept; + E&& error() && noexcept; + const E&& error() const&& noexcept; + private: + E @\exposid{val}@; // \expos + }; +} +\end{codeblock} + +\pnum +The class template \tcode{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 \tcode{expected} object +for which \tcode{has_value()} is \tcode{false}. + +\indexlibraryctor{bad_expected_access}% +\begin{itemdecl} +explicit bad_expected_access(E e); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{val} with \tcode{std::move(e)}. +\end{itemdescr} + +\indexlibrarymember{error}{bad_expected_access}% +\begin{itemdecl} +const E& error() const& noexcept; +E& error() & noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\exposid{val}. +\end{itemdescr} + +\indexlibrarymember{error}{bad_expected_access}% +\begin{itemdecl} +E&& error() && noexcept; +const E&& error() const&& noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{std::move(\exposid{val})}. +\end{itemdescr} + +\indexlibrarymember{what}{bad_expected_access}% +\begin{itemdecl} +const char* what() const noexcept override; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +An implementation-defined \ntbs. +\end{itemdescr} + +\rSec2[expected.bad.void]{Class template specialization \tcode{bad_expected_access}} + +\begin{codeblock} +namespace std { + template<> + class bad_expected_access : public exception { + protected: + bad_expected_access() noexcept; + bad_expected_access(const bad_expected_access&); + bad_expected_access(bad_expected_access&&); + bad_expected_access& operator=(const bad_expected_access&); + bad_expected_access& operator=(bad_expected_access&&); + ~bad_expected_access(); + public: + const char* what() const noexcept override; + }; +} +\end{codeblock} + +\indexlibrarymember{what}{bad_expected_access}% +\begin{itemdecl} +const char* what() const noexcept override; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +An implementation-defined \ntbs. +\end{itemdescr} + +\rSec2[expected.expected]{Class template \tcode{expected}} + +\rSec3[expected.object.general]{General} + +\begin{codeblock} +namespace std { + template + class expected { + public: + using @\libmember{value_type}{expected}@ = T; + using @\libmember{error_type}{expected}@ = E; + using @\libmember{unexpected_type}{expected}@ = unexpected; + + template + using @\libmember{rebind}{expected}@ = expected; + + // \ref{expected.object.ctor}, constructors + constexpr expected(); + constexpr explicit(@\seebelow@) expected(const expected&); + constexpr explicit(@\seebelow@) expected(expected&&) noexcept(@\seebelow@); + template + constexpr explicit(@\seebelow@) expected(const expected&); + template + constexpr explicit(@\seebelow@) expected(expected&&); + + template + constexpr explicit(@\seebelow@) expected(U&& v); + + template + constexpr expected(const unexpected&); + template + constexpr expected(unexpected&&); + + template + constexpr explicit expected(in_place_t, Args&&...); + template + constexpr explicit expected(in_place_t, initializer_list, Args&&...); + template + constexpr explicit expected(unexpect_t, Args&&...); + template + constexpr explicit expected(unexpect_t, initializer_list, Args&&...); + + // \ref{expected.object.dtor}, destructor + constexpr ~expected(); + + // \ref{expected.object.assign}, assignment + constexpr expected& operator=(const expected&); + constexpr expected& operator=(expected&&) noexcept(@\seebelow@); + template constexpr expected& operator=(U&&); + template + constexpr expected& operator=(const unexpected&); + template + constexpr expected& operator=(unexpected&&); + + template + constexpr T& emplace(Args&&...) noexcept; + template + constexpr T& emplace(initializer_list, Args&&...) noexcept; + + // \ref{expected.object.swap}, swap + constexpr void swap(expected&) noexcept(@\seebelow@); + friend constexpr void swap(expected&, expected&) noexcept(@\seebelow@); + + // \ref{expected.object.obs}, observers + 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 const T& value() const&; + constexpr T& value() &; + constexpr const T&& value() const&&; + constexpr T&& value() &&; + constexpr const E& error() const&; + constexpr E& error() &; + constexpr const E&& error() const&&; + constexpr E&& error() &&; + template constexpr T value_or(U&&) const&; + template constexpr T value_or(U&&) &&; + + // \ref{expected.object.eq}, equality operators + template + friend constexpr bool operator==(const expected& x, const expected& y); + template + friend constexpr bool operator==(const expected&, const T2&); + template + friend constexpr bool operator==(const expected&, const unexpected&); + + private: + bool @\exposid{has_val}@; // \expos + union { + T @\exposid{val}@; // \expos + E @\exposid{unex}@; // \expos + }; + }; +} +\end{codeblock} + +\pnum +Any object of type \tcode{expected} either +contains a value of type \tcode{T} or +a value of type \tcode{E} within its own storage. +Implementations are not permitted to use additional storage, +such as dynamic memory, +to allocate the object of type \tcode{T} or the object of type E. +These objects are allocated in a region of the \tcode{expected} storage +suitably aligned for the types \tcode{T} and \tcode{E}. +Members \exposid{has_val}, \exposid{val}, and \exposid{unex} +are provided for exposition only. +\exposid{has_val} indicates whether the \tcode{expected} object +contains an object of type \tcode{T}. + +\pnum +A program +that instantiates the definition of template \tcode{expected} +for a reference type, a function type, or +for possibly cv-qualified types \tcode{in_place_t}, \tcode{unexpect_t}, or +a specialization of \tcode{unexpected} for the \tcode{T} parameter +is ill-formed. +A program that instantiates +the definition of the template \tcode{expected} +with a type for the \tcode{E} parameter +that is not a valid template argument for \tcode{unexpected} is ill-formed. + +\pnum +When \tcode{T} is not \cv{} \tcode{void}, it shall meet +the \oldconcept{Destructible} requirements (\tref{cpp17.destructible}). +\tcode{E} shall meet +the \oldconcept{Destructible} requirements. + +\rSec3[expected.object.ctor]{Constructors} + +\indexlibraryctor{expected}% +\begin{itemdecl} +constexpr expected(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_default_constructible_v} is \tcode{true}. + +\pnum +\effects +Value-initializes \exposid{val}. + +\pnum +\ensures +\tcode{has_value()} is \tcode{true}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{val}. +\end{itemdescr} + +\indexlibraryctor{expected}% +\begin{itemdecl} +constexpr expected(const expected& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +If \tcode{rhs.has_value()} is \tcode{true}, +direct-non-list-initializes \exposid{val} with \tcode{*rhs}. +Otherwise, direct-non-list-initializes \exposid{unex} with \tcode{rhs.error()}. + +\pnum +\ensures +\tcode{rhs.has_value() == this->has_value()}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{val} or \exposid{unex}. + +\pnum +\remarks +This constructor is defined as deleted unless +\begin{itemize} +\item +\tcode{is_copy_constructible_v} is \tcode{true} and +\item +\tcode{is_copy_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +This constructor is trivial if +\begin{itemize} +\item +\tcode{is_trivially_copy_constructible_v} is \tcode{true} and +\item +\tcode{is_trivially_copy_constructible_v} is \tcode{true}. +\end{itemize} +\end{itemdescr} + +\indexlibraryctor{expected}% +\begin{itemdecl} +constexpr expected(expected&& rhs) noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_move_constructible_v} is \tcode{true} and +\item +\tcode{is_move_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +If \tcode{rhs.has_value()} is \tcode{true}, +direct-non-list-initializes \exposid{val} with \tcode{std::move(*rhs)}. +Otherwise, +direct-non-list-initializes \exposid{unex} with \tcode{std::move(rhs.error())}. + +\pnum +\ensures +\tcode{rhs.has_value()} is unchanged; +\tcode{rhs.has_value() == this->has_value()} is \tcode{true}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{val} or \exposid{unex}. + +\pnum +\remarks +The exception specification is +\tcode{is_nothrow_move_constructible_v \&\& +is_nothrow_move_constructible_v}. + +\pnum +This constructor is trivial if +\begin{itemize} +\item +\tcode{is_trivially_move_constructible_v} is \tcode{true} and +\item +\tcode{is_trivially_move_constructible_v} is \tcode{true}. +\end{itemize} +\end{itemdescr} + +\indexlibraryctor{expected}% +\begin{itemdecl} +template + constexpr explicit(@\seebelow@) expected(const expected& rhs); +template + constexpr explicit(@\seebelow@) expected(expected&& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let: +\begin{itemize} +\item +\tcode{UF} be \tcode{const U\&} for the first overload and +\tcode{U} for the second overload. +\item +\tcode{GF} be \tcode{const G\&} for the first overload and +\tcode{G} for the second overload. +\end{itemize} + +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_constructible_v} is \tcode{true}; and +\item +\tcode{is_constructible_v} is \tcode{true}; and +\item +\tcode{is_constructible_v\&>} is \tcode{false}; and +\item +\tcode{is_constructible_v>} is \tcode{false}; and +\item +\tcode{is_constructible_v\&>} is \tcode{false}; and +\item +\tcode{is_constructible_v>} is \tcode{false}; and +\item +\tcode{is_convertible_v\&, T>} is \tcode{false}; and +\item +\tcode{is_convertible_v\&\&, T>} is \tcode{false}; and +\item +\tcode{is_convertible_v\&, T>} is \tcode{false}; and +\item +\tcode{is_convertible_v\&\&, T>} is \tcode{false}; and +\item +\tcode{is_constructible_v, expected\&>} is \tcode{false}; and +\item +\tcode{is_constructible_v, expected>} is \tcode{false}; and +\item +\tcode{is_constructible_v, const expected\&>} is \tcode{false}; and +\item +\tcode{is_constructible_v, const expected>} is \tcode{false}. +\end{itemize} + +\pnum +\effects +If \tcode{rhs.has_value()}, +direct-non-list-initializes \exposid{val} with \tcode{std::forward(*rhs)}. +Otherwise, +direct-non-list-initializes \exposid{unex} with \tcode{std::forward(rhs.error())}. + +\pnum +\ensures +\tcode{rhs.has_value()} is unchanged; +\tcode{rhs.has_value() == this->has_value()} is \tcode{true}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{val} or \exposid{unex}. + +\pnum +\remarks +The expression inside \tcode{explicit} is equivalent to +\tcode{!is_convertible_v || !is_convertible_v}. +\end{itemdescr} + +\indexlibraryctor{expected}% +\begin{itemdecl} +template + constexpr explicit(!is_convertible_v) expected(U&& v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_same_v, in_place_t>} is \tcode{false}; and +\item +\tcode{is_same_v, remove_cvref_t>} is \tcode{false}; and +\item +\tcode{remove_cvref_t} is not a specialization of \tcode{unexpected}; and +\item +\tcode{is_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Direct-non-list-initializes \exposid{val} with \tcode{std::forward(v)}. + +\pnum +\ensures +\tcode{has_value()} is \tcode{true}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{val}. +\end{itemdescr} + +\indexlibraryctor{expected}% +\begin{itemdecl} +template + constexpr explicit(!is_convertible_v) expected(const unexpected& e); +template + constexpr explicit(!is_convertible_v) expected(unexpected&& e); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{GF} be \tcode{const G\&} for the first overload and +\tcode{G} for the second overload. + +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\effects +Direct-non-list-initializes \exposid{unex} with \tcode{std::forward(e.error())}. + +\pnum +\ensures +\tcode{has_value()} is \tcode{false}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{unex}. +\end{itemdescr} + +\indexlibraryctor{expected}% +\begin{itemdecl} +template + constexpr explicit expected(in_place_t, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\effects +Direct-non-list-initializes \exposid{val} with \tcode{std::forward(args)...}. + +\pnum +\ensures +\tcode{has_value()} is \tcode{true}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{val}. +\end{itemdescr} + +\indexlibraryctor{expected}% +\begin{itemdecl} +template + constexpr explicit expected(in_place_t, initializer_list il, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v\&, Args...>} is \tcode{true}. + +\pnum +\effects +Direct-non-list-initializes \exposid{val} with +\tcode{il, std::forward(args)...}. + +\pnum +\ensures +\tcode{has_value()} is \tcode{true}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{val}. +\end{itemdescr} + +\indexlibraryctor{expected}% +\begin{itemdecl} +template + constexpr explicit expected(unexpect_t, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\effects +Direct-non-list-initializes \exposid{unex} with +\tcode{std::forward(args)...}. + +\pnum +\ensures +\tcode{has_value()} is \tcode{false}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{unex}. +\end{itemdescr} + +\indexlibraryctor{expected}% +\begin{itemdecl} +template + constexpr explicit expected(unexpect_t, initializer_list il, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v\&, Args...>} is \tcode{true}. + +\pnum +\effects +Direct-non-list-initializes \exposid{unex} with +\tcode{il, std::forward(args)...}. + +\pnum +\ensures +\tcode{has_value()} is \tcode{false}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{unex}. +\end{itemdescr} + +\rSec3[expected.object.dtor]{Destructor} + +\indexlibrarydtor{expected}% +\begin{itemdecl} +constexpr ~expected(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +If \tcode{has_value()} is \tcode{true}, destroys \exposid{val}, +otherwise destroys \exposid{unex}. + +\pnum +\remarks +If \tcode{is_trivially_destructible_v} is \tcode{true}, and +\tcode{is_trivially_destructible_v} is \tcode{true}, +then this destructor is a trivial destructor. +\end{itemdescr} + +\rSec3[expected.object.assign]{Assignment} + +\pnum +This subclause makes use of the following exposition-only function: +\begin{codeblock} +template +constexpr void @\exposid{reinit-expected}@(T& newval, U& oldval, Args&&... args) { // \expos + if constexpr (is_nothrow_constructible_v) { + destroy_at(addressof(oldval)); + construct_at(addressof(newval), std::forward(args)...); + } else if constexpr (is_nothrow_move_constructible_v) { + T tmp(std::forward(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)...); + } catch (...) { + construct_at(addressof(oldval), std::move(tmp)); + throw; + } + } +} +\end{codeblock} + +\indexlibrarymember{operator=}{expected}% +\begin{itemdecl} +constexpr expected& operator=(const expected& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +\begin{itemize} +\item +If \tcode{this->has_value() \&\& rhs.has_value()} is \tcode{true}, +equivalent to \tcode{\exposid{val} = *rhs}. +\item +Otherwise, if \tcode{this->has_value()} is \tcode{true}, equivalent to: +\begin{codeblock} +@\exposid{reinit-expected}@(@\exposid{unex}@, @\exposid{val}@, rhs.error()) +\end{codeblock} +\item +Otherwise, if \tcode{rhs.has_value()} is \tcode{true}, equivalent to: +\begin{codeblock} +@\exposid{reinit-expected}@(@\exposid{val}@, @\exposid{unex}@, *rhs) +\end{codeblock} +\item +Otherwise, equivalent to \tcode{\exposid{unex} = rhs.error()}. +\end{itemize} +Then, if no exception was thrown, +equivalent to: \tcode{\exposid{has_val} = rhs.has_value(); return *this;} + +\pnum +\remarks +This operator is defined as deleted unless: +\begin{itemize} +\item +\tcode{is_copy_assignable_v} is \tcode{true} and +\item +\tcode{is_copy_constructible_v} is \tcode{true} and +\item +\tcode{is_copy_assignable_v} is \tcode{true} and +\item +\tcode{is_copy_constructible_v} is \tcode{true} and +\item +\tcode{is_nothrow_move_constructible_v || is_nothrow_move_constructible_v} +is \tcode{true}. +\end{itemize} +\end{itemdescr} + +\indexlibrarymember{operator=}{expected}% +\begin{itemdecl} +constexpr expected& operator=(expected&& rhs) noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_move_constructible_v} is \tcode{true} and +\item +\tcode{is_move_assignable_v} is \tcode{true} and +\item +\tcode{is_move_constructible_v} is \tcode{true} and +\item +\tcode{is_move_assignable_v} is \tcode{true} and +\item +\tcode{is_nothrow_move_constructible_v || is_nothrow_move_constructible_v} +is \tcode{true}. +\end{itemize} + +\pnum +\effects +\begin{itemize} +\item +If \tcode{this->has_value() \&\& rhs.has_value()} is \tcode{true}, +equivalent to \tcode{\exposid{val} = std::move(*rhs)}. +\item +Otherwise, if \tcode{this->has_value()} is \tcode{true}, equivalent to: +\begin{codeblock} +@\exposid{reinit-expected}@(@\exposid{unex}@, @\exposid{val}@, std::move(rhs.error())) +\end{codeblock} +\item +Otherwise, if \tcode{rhs.has_value()} is \tcode{true}, equivalent to: +\begin{codeblock} +@\exposid{reinit-expected}@(@\exposid{val}@, @\exposid{unex}@, std::move(*rhs)) +\end{codeblock} +\item +Otherwise, equivalent to \tcode{\exposid{unex} = std::move(rhs.error())}. +\end{itemize} +Then, if no exception was thrown, +equivalent to: \tcode{has_val = rhs.has_value(); return *this;} + +\pnum +\remarks +The exception specification is +\begin{codeblock} +is_nothrow_move_assignable_v && is_nothrow_move_constructible_v && +is_nothrow_move_assignable_v && is_nothrow_move_constructible_v +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator=}{expected}% +\begin{itemdecl} +template + constexpr expected& operator=(U&& v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_same_v>} is \tcode{false}; and +\item +\tcode{remove_cvref_t} is not a specialization of \tcode{unexpected}; and +\item +\tcode{is_constructible_v} is \tcode{true}; and +\item +\tcode{is_assignable_v} is \tcode{true}; and +\item +\tcode{is_nothrow_constructible_v || is_nothrow_move_constructible_v ||\newline +is_nothrow_move_constructible_v} +is \tcode{true}. +\end{itemize} + +\pnum +\effects +\begin{itemize} +\item +If \tcode{has_value()} is \tcode{true}, +equivalent to: \tcode{\exposid{val} = std::forward(v);} +\item +Otherwise, equivalent to: +\begin{codeblock} +@\exposid{reinit-expected}@(@\exposid{val}@, @\exposid{unex}@, std::forward(v)); +@\exposid{has_val}@ = true; +\end{codeblock} +\end{itemize} + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + +\indexlibrarymember{operator=}{expected}% +\begin{itemdecl} +template + constexpr expected& operator=(const unexpected& e); +template + constexpr expected& operator=(unexpected&& e); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{GF} be \tcode{const G\&} for the first overload and +\tcode{G} for the second overload. + +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_constructible_v} is \tcode{true}; and +\item +\tcode{is_assignable_v} is \tcode{true}; and +\item +\tcode{is_nothrow_constructible_v || is_nothrow_move_constructible_v ||\newline +is_nothrow_move_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +\begin{itemize} +\item +If \tcode{has_value()} is \tcode{true}, equivalent to: +\begin{codeblock} +@\exposid{reinit-expected}@(@\exposid{unex}@, @\exposid{val}@, std::forward(e.value())); +@\exposid{has_val}@ = false; +\end{codeblock} +\item +Otherwise, equivalent to: +\tcode{\exposid{unex} = std::forward(e.value());} +\end{itemize} + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + +\indexlibrarymember{emplace}{expected}% +\begin{itemdecl} +template + constexpr T& emplace(Args&&... args) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_nothrow_constructible_v} is \tcode{true}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +if (has_value()) { + destroy_at(addressof(@\exposid{val}@)); +} else { + destroy_at(addressof(@\exposid{unex}@)); + @\exposid{has_val}@ = true; +} +return *construct_at(addressof(@\exposid{val}@), std::forward(args)...); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{emplace}{expected}% +\begin{itemdecl} +template + constexpr T& emplace(initializer_list il, Args&&... args) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_nothrow_constructible_v\&, Args...>} +is \tcode{true}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +if (has_value()) { + destroy_at(addressof(@\exposid{val}@)); +} else { + destroy_at(addressof(@\exposid{unex}@)); + @\exposid{has_val}@ = true; +} +return *construct_at(addressof(@\exposid{val}@), il, std::forward(args)...); +\end{codeblock} +\end{itemdescr} + +\rSec3[expected.object.swap]{Swap} + +\indexlibrarymember{swap}{expected}% +\begin{itemdecl} +constexpr void swap(expected& rhs) noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_swappable_v} is \tcode{true} and +\item +\tcode{is_swappable_v} is \tcode{true} and +\item +\tcode{is_move_constructible_v \&\& is_move_constructible_v} +is \tcode{true}, and +\item +\tcode{is_nothrow_move_constructible_v || is_nothrow_move_constructible_v} +is \tcode{true}. +\end{itemize} + +\pnum +\effects +See \tref{expected.object.swap}. + +\begin{floattable}{\tcode{swap(expected\&)} effects}{expected.object.swap} +{lx{0.35\hsize}x{0.35\hsize}} +\topline +& \chdr{\tcode{this->has_value()}} & \rhdr{\tcode{!has_value()}} \\ \capsep +\lhdr{\tcode{rhs.has_value()}} & + equivalent to: \tcode{using std::swap; swap(\exposid{val}, rhs.\exposid{val});} & + calls \tcode{rhs.swap(*this)} \\ +\lhdr{\tcode{!rhs.has_value()}} & + \seebelow & + equivalent to: \tcode{using std::swap; swap(\exposid{unex}, rhs.\exposid{unex});} \\ +\end{floattable} + +For the case where \tcode{rhs.value()} is \tcode{false} and +\tcode{this->has_value()} is \tcode{true}, equivalent to: +\begin{codeblock} +if constexpr (is_nothrow_move_constructible_v) { + E tmp(std::move(rhs.@\exposid{unex}@)); + destroy_at(addressof(rhs.@\exposid{unex}@)); + try { + construct_at(addressof(rhs.@\exposid{val}@), std::move(@\exposid{val}@)); + destroy_at(addressof(@\exposid{val}@)); + construct_at(addressof(@\exposid{unex}@), std::move(tmp)); + } catch(...) { + construct_at(addressof(rhs.@\exposid{unex}@), std::move(tmp)); + throw; + } +} else { + T tmp(std::move(@\exposid{val}@)); + destroy_at(addressof(@\exposid{val}@)); + try { + construct_at(addressof(@\exposid{unex}@), std::move(rhs.@\exposid{unex}@)); + destroy_at(addressof(rhs.@\exposid{unex}@)); + construct_at(addressof(rhs.@\exposid{val}@), std::move(tmp)); + } catch (...) { + construct_at(addressof(@\exposid{val}@), std::move(tmp)); + throw; + } +} +@\exposid{has_val}@ = false; +rhs.@\exposid{has_val}@ = true; +\end{codeblock} + +\pnum +\throws +Any exception thrown by the expressions in the \Fundescx{Effects}. + +\pnum +\remarks +The exception specification is: +\begin{codeblock} +is_nothrow_move_constructible_v && is_nothrow_swappable_v && +is_nothrow_move_constructible_v && is_nothrow_swappable_v +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{swap}{expected}% +\begin{itemdecl} +friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(x.swap(y))); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{x.swap(y)}. +\end{itemdescr} + +\rSec3[expected.object.obs]{Observers} + +\indexlibrarymember{operator->}{expected}% +\begin{itemdecl} +constexpr const T* operator->() const noexcept; +constexpr T* operator->() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{has_value()} is \tcode{true}. + +\pnum +\returns +\tcode{addressof(\exposid{val})}. +\end{itemdescr} + +\indexlibrarymember{operator*}{expected}% +\begin{itemdecl} +constexpr const T& operator*() const& noexcept; +constexpr T& operator*() & noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{has_value()} is \tcode{true}. + +\pnum +\returns +\exposid{val}. +\end{itemdescr} + +\indexlibrarymember{operator*}{expected}% +\begin{itemdecl} +constexpr T&& operator*() && noexcept; +constexpr const T&& operator*() const&& noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{has_value()} is \tcode{true}. + +\pnum +\returns +\tcode{std::move(\exposid{val})}. +\end{itemdescr} + +\indexlibrarymember{operator bool}{expected}% +\indexlibrarymember{has_value}{expected}% +\begin{itemdecl} +constexpr explicit operator bool() const noexcept; +constexpr bool has_value() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\exposid{has_val}. +\end{itemdescr} + +\indexlibrarymember{value}{expected}% +\begin{itemdecl} +constexpr const T& value() const&; +constexpr T& value() &; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\exposid{val}, if \tcode{has_value()} is \tcode{true}. + +\pnum +\throws +\tcode{bad_expected_access(error())} if \tcode{has_value()} is \tcode{false}. +\end{itemdescr} + +\indexlibrarymember{value}{expected}% +\begin{itemdecl} +constexpr T&& value() &&; +constexpr const T&& value() const&&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{std::move(\exposid{val})}, if \tcode{has_value()} is \tcode{true}. + +\pnum +\throws +\tcode{bad_expected_access(std::move(error()))} +if \tcode{has_value()} is \tcode{false}. +\end{itemdescr} + +\indexlibrarymember{error}{expected}% +\begin{itemdecl} +constexpr const E& error() const& noexcept; +constexpr E& error() & noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{has_value()} is \tcode{false}. + +\pnum +\returns +\exposid{unex}. +\end{itemdescr} + +\indexlibrarymember{error}{expected}% +\begin{itemdecl} +constexpr E&& error() && noexcept; +constexpr const E&& error() const&& noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{has_value()} is \tcode{false}. + +\pnum +\returns +\tcode{std::move(\exposid{unex})}. +\end{itemdescr} + +\indexlibrarymember{value_or}{expected}% +\begin{itemdecl} +template constexpr T value_or(U&& v) const&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{is_copy_constructible_v} is \tcode{true} and +\tcode{is_convertible} is \tcode{true}. + +\pnum +\returns +\tcode{has_value() ? **this : static_cast(std::forward(v))}. +\end{itemdescr} + +\indexlibrarymember{value_or}{expected}% +\begin{itemdecl} +template constexpr T value_or(U&& v) &&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{is_move_constructible_v} is \tcode{true} and +\tcode{is_convertible} is \tcode{true}. + +\pnum +\returns +\tcode{has_value() ? std::move(**this) : static_cast(std::forward(v))}. +\end{itemdescr} + +\rSec3[expected.object.eq]{Equality operators} + +\indexlibrarymember{operator==}{expected}% +\begin{itemdecl} +template requires (!is_void_v) + friend constexpr bool operator==(const expected& x, const expected& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +The expressions \tcode{*x == *y} and \tcode{x.error() == y.error()} +are well-formed and their results are convertible to \tcode{bool}. + +\pnum +\returns +If \tcode{x.has_value()} does not equal \tcode{y.has_value()}, \tcode{false}; +otherwise if \tcode{x.has_value()} is \tcode{true}, \tcode{*x == *y}; +otherwise \tcode{x.error() == y.error()}. +\end{itemdescr} + +\indexlibrarymember{operator==}{expected}% +\begin{itemdecl} +template constexpr bool operator==(const expected& x, const T2& v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +The expression \tcode{*x == v} is well-formed and +its result is convertible to \tcode{bool}. +\begin{note} +\tcode{T1} need not be \oldconcept{EqualityComparable}. +\end{note} + +\pnum +\returns +\tcode{x.has_value() \&\& static_cast(*x == v)}. +\end{itemdescr} + +\indexlibrarymember{operator==}{expected}% +\begin{itemdecl} +template constexpr bool operator==(const expected& x, const unexpected& e); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +The expression \tcode{x.error() == e.value()} is well-formed and +its result is convertible to \tcode{bool}. + +\pnum +\returns +\tcode{!x.has_value() \&\& static_cast(x.error() == e.value())}. +\end{itemdescr} + +\rSec2[expected.void]{Partial specialization of \tcode{expected} for \tcode{void} types} + +\rSec3[expected.void.general]{General} + +\begin{codeblock} +template requires is_void_v +class expected { +public: + using @\libmember{value_type}{expected}@ = T; + using @\libmember{error_type}{expected}@ = E; + using @\libmember{unexpected_type}{expected}@ = unexpected; + + template + using @\libmember{rebind}{expected}@ = expected; + + // \ref{expected.void.ctor}, constructors + constexpr expected() noexcept; + constexpr explicit(@\seebelow@) expected(const expected&); + constexpr explicit(@\seebelow@) expected(expected&&) noexcept(@\seebelow@); + template + constexpr explicit(@\seebelow@) expected(const expected&); + template + constexpr explicit(@\seebelow@) expected(expected&&); + + template + constexpr expected(const unexpected&); + template + constexpr expected(unexpected&&); + + constexpr explicit expected(in_place_t) noexcept; + template + constexpr explicit expected(unexpect_t, Args&&...); + template + constexpr explicit expected(unexpect_t, initializer_list, Args&&...); + + + // \ref{expected.void.dtor}, destructor + constexpr ~expected(); + + // \ref{expected.void.assign}, assignment + constexpr expected& operator=(const expected&); + constexpr expected& operator=(expected&&) noexcept(@\seebelow@); + template + constexpr expected& operator=(const unexpected&); + template + constexpr expected& operator=(unexpected&&); + constexpr void emplace() noexcept; + + // \ref{expected.void.swap}, swap + constexpr void swap(expected&) noexcept(@\seebelow@); + friend constexpr void swap(expected&, expected&) noexcept(@\seebelow@); + + // \ref{expected.void.obs}, observers + constexpr explicit operator bool() const noexcept; + constexpr bool has_value() const noexcept; + constexpr void operator*() const noexcept; + constexpr void value() const&; + constexpr void value() &&; + constexpr const E& error() const&; + constexpr E& error() &; + constexpr const E&& error() const&&; + constexpr E&& error() &&; + + // \ref{expected.void.eq}, equality operators + template requires is_void_v + friend constexpr bool operator==(const expected& x, const expected& y); + template + friend constexpr bool operator==(const expected&, const unexpected&); + +private: + bool @\exposid{has_val}@; // \expos + union { + E @\exposid{unex}@; // \expos + }; +}; +\end{codeblock} + +\pnum +\tcode{E} shall meet the requirements of +\oldconcept{Destructible} (\tref{cpp17.destructible}). + +\rSec3[expected.void.ctor]{Constructors} + +\indexlibraryctor{expected}% +\begin{itemdecl} +constexpr expected() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ensures +\tcode{has_value()} is \tcode{true}. +\end{itemdescr} + +\indexlibraryctor{expected}% +\begin{itemdecl} +constexpr expected(const expected& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +If \tcode{rhs.has_value()} is \tcode{false}, +direct-non-list-initializes \exposid{unex} with \tcode{rhs.error()}. + +\pnum +\ensures +\tcode{rhs.has_value() == this->has_value()}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{unex}. + +\pnum +\remarks +This constructor is defined as deleted +unless \tcode{is_copy_constructible_v} is \tcode{true}. + +\pnum +This constructor is trivial +if \tcode{is_trivially_copy_constructible_v} is \tcode{true}. +\end{itemdescr} + +\indexlibraryctor{expected}% +\begin{itemdecl} +constexpr expected(expected&& rhs) noexcept(is_nothrow_move_constructible_v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_move_constructible_v} is \tcode{true}. + +\pnum +\effects +If \tcode{rhs.has_value()} is \tcode{false}, +direct-non-list-initializes \exposid{unex} with \tcode{std::move(rhs.error())}. + +\pnum +\ensures +\tcode{rhs.has_value()} is unchanged; +\tcode{rhs.has_value() == this->has_value()} is \tcode{true}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{unex}. + +\pnum +\remarks +This constructor is trivial +if \tcode{is_trivially_move_constructible_v} is \tcode{true}. +\end{itemdescr} + +\indexlibraryctor{expected}% +\begin{itemdecl} +template + constexpr explicit(!is_convertible_v) expected(const expected& rhs); +template + constexpr explicit(!is_convertible_v) expected(expected&& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{GF} be \tcode{const G\&} for the first overload and +\tcode{G} for the second overload. + +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_void_v} is \tcode{true}; and +\item +\tcode{is_constructible_v} is \tcode{true}; and +\item +\tcode{is_constructible_v, expected\&>} +is \tcode{false}; and +\item +\tcode{is_constructible_v, expected>} +is \tcode{false}; and +\item +\tcode{is_constructible_v, const expected\&>} +is \tcode{false}; and +\item +\tcode{is_constructible_v, const expected>} +is \tcode{false}. +\end{itemize} + +\pnum +\effects +If \tcode{rhs.has_value()} is \tcode{false}, +direct-non-list-initializes \exposid{unex} +with \tcode{std::forward(rhs.er\-ror())}. + +\pnum +\ensures +\tcode{rhs.has_value()} is unchanged; +\tcode{rhs.has_value() == this->has_value()} is \tcode{true}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{unex}. +\end{itemdescr} + +\indexlibraryctor{expected}% +\begin{itemdecl} +template + constexpr explicit(!is_convertible_v) expected(const unexpected& e); +template + constexpr explicit(!is_convertible_v) expected(unexpected&& e); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{GF} be \tcode{const G\&} for the first overload and +\tcode{G} for the second overload. + +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\effects +Direct-non-list-initializes \exposid{unex} +with \tcode{std::forward(e.value())}. + +\pnum +\ensures +\tcode{has_value()} is \tcode{false}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{unex}. +\end{itemdescr} + +\indexlibraryctor{expected}% +\begin{itemdecl} +constexpr explicit expected(in_place_t) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ensures +\tcode{has_value()} is \tcode{true}. +\end{itemdescr} + +\indexlibraryctor{expected}% +\begin{itemdecl} +template + constexpr explicit expected(unexpect_t, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\effects +Direct-non-list-initializes \exposid{unex} +with \tcode{std::forward(args)...}. + +\pnum +\ensures +\tcode{has_value()} is \tcode{false}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{unex}. +\end{itemdescr} + +\indexlibraryctor{expected}% +\begin{itemdecl} +template + constexpr explicit expected(unexpect_t, initializer_list il, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v\&, Args...>} is \tcode{true}. + +\pnum +\effects +Direct-non-list-initializes \exposid{unex} +with \tcode{il, std::forward(args)...}. + +\pnum +\ensures +\tcode{has_value()} is \tcode{false}. + +\pnum +\throws +Any exception thrown by the initialization of \exposid{unex}. +\end{itemdescr} + +\rSec3[expected.void.dtor]{Destructor} + +\indexlibrarydtor{expected}% +\begin{itemdecl} +constexpr ~expected(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +If \tcode{has_value()} is \tcode{false}, destroys \exposid{unex}. + +\pnum +\remarks +If \tcode{is_trivially_destructible_v} is \tcode{true}, +then this destructor is a trivial destructor. +\end{itemdescr} + +\rSec3[expected.void.assign]{Assignment} + +\indexlibrarymember{operator=}{expected}% +\begin{itemdecl} +constexpr expected& operator=(const expected& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +\begin{itemize} +\item +If \tcode{this->has_value() \&\& rhs.has_value()} is \tcode{true}, no effects. +\item +Otherwise, if \tcode{this->has_value()} is \tcode{true}, +equivalent to: \tcode{construct_at(addressof(\exposid{unex}), rhs.\exposid{unex}); \exposid{has_val} = false;} +\item +Otherwise, if \tcode{rhs.has_value()} is \tcode{true}, +destroys \exposid{unex} and sets \exposid{has_val} to \tcode{true}. +\item +Otherwise, equivalent to \tcode{\exposid{unex} = rhs.error()}. +\end{itemize} + +\pnum +\returns +\tcode{*this}. + +\pnum +\remarks +This operator is defined as deleted unless +\tcode{is_copy_assignable_v} is \tcode{true} and +\tcode{is_copy_constructible_v} is \tcode{true}. +\end{itemdescr} + +\indexlibrarymember{operator=}{expected}% +\begin{itemdecl} +constexpr expected& operator=(expected&& rhs) noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +\begin{itemize} +\item +If \tcode{this->has_value() \&\& rhs.has_value()} is \tcode{true}, no effects. +\item +Otherwise, if \tcode{this->has_value()} is \tcode{true}, equivalent to: +\begin{codeblock} +construct_at(addressof(@\exposid{unex}@), std::move(rhs.@\exposid{unex}@)); +@\exposid{has_val}@ = false; +\end{codeblock} +\item +Otherwise, if \tcode{rhs.has_value()} is \tcode{true}, +destroys \exposid{unex} and sets \exposid{has_val} to \tcode{true}. +\item +Otherwise, equivalent to \tcode{\exposid{unex} = rhs.error()}. +\end{itemize} + +\pnum +\returns +\tcode{*this}. + +\pnum +\remarks +The exception specification is +\tcode{is_nothrow_move_constructible_v \&\& is_nothrow_move_assignable_v}. + +\pnum +This operator is defined as deleted unless +\tcode{is_move_constructible_v} is \tcode{true} and +\tcode{is_move_assignable_v} is \tcode{true}. +\end{itemdescr} + +\indexlibrarymember{operator=}{expected}% +\begin{itemdecl} +template + constexpr expected& operator=(const unexpected& e); +template + constexpr expected& operator=(unexpected&& e); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{GF} be \tcode{const G\&} for the first overload and +\tcode{G} for the second overload. + +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true} and +\tcode{is_assignable_v} is \tcode{true}. + +\pnum +\effects +\begin{itemize} +\item +If \tcode{has_value()} is \tcode{true}, equivalent to: +\begin{codeblock} +construct_at(addressof(@\exposid{unex}@), std::forward(e.value())); +@\exposid{has_val}@ = false; +\end{codeblock} +\item +Otherwise, equivalent to: +\tcode{\exposid{unex} = std::forward(e.value());} +\end{itemize} + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + +\indexlibrarymember{emplace}{expected}% +\begin{itemdecl} +constexpr void emplace() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +If \tcode{has_value()} is \tcode{false}, +destroys \exposid{unex} and sets \exposid{has_val} to \tcode{true}. +\end{itemdescr} + +\rSec3[expected.void.swap]{Swap} + +\indexlibrarymember{swap}{expected}% +\begin{itemdecl} +constexpr void swap(expected& rhs) noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_swappable_v} is \tcode{true} and +\tcode{is_move_constructible_v} is \tcode{true}. + +\pnum +\effects +See \tref{expected.void.swap}. + +\begin{floattable}{\tcode{swap(expected\&)} effects}{expected.void.swap} +{lx{0.35\hsize}x{0.35\hsize}} +\topline +& \chdr{\tcode{this->has_value()}} & \rhdr{\tcode{!has_value()}} \\ \capsep +\lhdr{\tcode{rhs.has_value()}} & + no effects & + calls \tcode{rhs.swap(*this)} \\ +\lhdr{\tcode{!rhs.has_value()}} & + \seebelow & + equivalent to: \tcode{using std::swap; swap(\exposid{unex}, rhs.\exposid{unex});} \\ +\end{floattable} + +For the case where \tcode{rhs.value()} is \tcode{false} and +\tcode{this->has_value()} is \tcode{true}, equivalent to: +\begin{codeblock} +construct_at(addressof(@\exposid{unex}@), std::move(rhs.@\exposid{unex}@)); +destroy_at(addressof(rhs.@\exposid{unex}@)); +@\exposid{has_val}@ = false; +rhs.@\exposid{has_val}@ = true; +\end{codeblock} + +\pnum +\throws +Any exception thrown by the expressions in the \Fundescx{Effects}. + +\pnum +\remarks +The exception specification is +\tcode{is_nothrow_move_constructible_v \&\& is_nothrow_swappable_v}. +\end{itemdescr} + +\indexlibrarymember{swap}{expected}% +\begin{itemdecl} +friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(x.swap(y))); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{x.swap(y)}. +\end{itemdescr} + +\rSec3[expected.void.obs]{Observers} + +\indexlibrarymember{operator bool}{expected}% +\indexlibrarymember{has_value}{expected}% +\begin{itemdecl} +constexpr explicit operator bool() const noexcept; +constexpr bool has_value() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\exposid{has_val}. +\end{itemdescr} + +\indexlibrarymember{operator*}{expected}% +\begin{itemdecl} +constexpr void operator*() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{has_value()} is \tcode{true}. +\end{itemdescr} + +\indexlibrarymember{value}{expected}% +\begin{itemdecl} +constexpr void value() const&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\throws +\tcode{bad_expected_access(error())} if \tcode{has_value()} is \tcode{false}. +\end{itemdescr} + +\indexlibrarymember{value}{expected}% +\begin{itemdecl} +constexpr void value() &&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\throws +\tcode{bad_expected_access(std::move(error()))} +if \tcode{has_value()} is \tcode{false}. +\end{itemdescr} + +\indexlibrarymember{error}{expected}% +\begin{itemdecl} +constexpr const E& error() const&; +constexpr E& error() &; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{has_value()} is \tcode{false}. + +\pnum +\returns +\exposid{unex}. +\end{itemdescr} + +\indexlibrarymember{error}{expected}% +\begin{itemdecl} +constexpr E&& error() &&; +constexpr const E&& error() const&&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{has_value()} is \tcode{false}. + +\pnum +\returns +\tcode{std::move(\exposid{unex})}. +\end{itemdescr} + +\rSec3[expected.void.eq]{Equality operators} + +\indexlibrarymember{operator==}{expected}% +\begin{itemdecl} +template requires is_void_v + friend constexpr bool operator==(const expected& x, const expected& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +The expression \tcode{x.error() == y.error()} is well-formed and +its result is convertible to \tcode{bool}. + +\pnum +\returns +If \tcode{x.has_value()} does not equal \tcode{y.has_value()}, \tcode{false}; +otherwise \tcode{x.has_value() || static_cast(x.error() == y.error())}. +\end{itemdescr} + +\indexlibrarymember{operator==}{expected}% +\begin{itemdecl} +template + friend constexpr bool operator==(const expected& x, const unexpected& e); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +The expression \tcode{x.error() == e.value()} is well-formed and +its result is convertible to \tcode{bool}. + +\pnum +\returns +\tcode{!x.has_value() \&\& static_cast(x.error() == e.value())}. +\end{itemdescr} + \rSec1[bitset]{Bitsets} \indexlibraryglobal{bitset}% From 71f6e85eaa6bba99f6901074eebeabc9f3352719 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Fri, 11 Feb 2022 10:27:27 +0100 Subject: [PATCH 2/2] [expected] Fixes for issues introduced with P0323R12. Includes fixing a misspelled function name in [expected.object.ctor] and misspelled parameters in [expected.un.ctor]. Changes "This subclause" to "Subclause " to accommodate the additional sectioning that was introduced to avoid hanging paragraphs. --- source/utilities.tex | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/source/utilities.tex b/source/utilities.tex index 6308313a8b..981ddd26c9 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -6470,7 +6470,7 @@ \rSec2[expected.general]{In general} \pnum -This subclause describes the class template \tcode{expected} +Subclause \ref{expected} describes the class template \tcode{expected} that represents expected objects. An \tcode{expected} object holds an object of type \tcode{T} or an object of type \tcode{unexpected} and @@ -6485,7 +6485,7 @@ // \ref{expected.un.object}, class template \tcode{unexpected} template class unexpected; - // \ref{expected.bad}, class \tcode{bad_expected_access} + // \ref{expected.bad}, class template \tcode{bad_expected_access} template class bad_expected_access; // \ref{expected.bad.void}, specialization for \tcode{void} @@ -6510,7 +6510,7 @@ \rSec3[expected.un.general]{General} \pnum -This subclause describes the class template \tcode{unexpected} +Subclause \ref{expected.unexpected} describes the class template \tcode{unexpected} that represents unexpected objects stored in \tcode{expected} objects. \rSec3[expected.un.object]{Class template \tcode{unexpected}} @@ -6595,7 +6595,7 @@ \indexlibraryctor{unexpected}% \begin{itemdecl} template - constexpr explicit unexpected(in_place_t, Args&&...); + constexpr explicit unexpected(in_place_t, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -6616,7 +6616,7 @@ \indexlibraryctor{unexpected}% \begin{itemdecl} template - constexpr explicit unexpected(in_place_t, initializer_list, Args&&...); + constexpr explicit unexpected(in_place_t, initializer_list il, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -6627,7 +6627,7 @@ \pnum \effects Direct-non-list-initializes -\exposid{val} with \tcode{std::forward(args)...}. +\exposid{val} with \tcode{il, std::forward(args)...}. \pnum \throws @@ -6874,7 +6874,7 @@ // \ref{expected.object.swap}, swap constexpr void swap(expected&) noexcept(@\seebelow@); - friend constexpr void swap(expected&, expected&) noexcept(@\seebelow@); + friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(x.swap(y))); // \ref{expected.object.obs}, observers constexpr const T* operator->() const noexcept; @@ -6897,7 +6897,7 @@ template constexpr T value_or(U&&) &&; // \ref{expected.object.eq}, equality operators - template + template requires (!is_void_v) friend constexpr bool operator==(const expected& x, const expected& y); template friend constexpr bool operator==(const expected&, const T2&); @@ -7044,7 +7044,7 @@ \pnum \remarks -The exception specification is +The exception specification is equivalent to \tcode{is_nothrow_move_constructible_v \&\& is_nothrow_move_constructible_v}. @@ -7185,7 +7185,7 @@ \pnum \effects -Direct-non-list-initializes \exposid{unex} with \tcode{std::forward(e.error())}. +Direct-non-list-initializes \exposid{unex} with \tcode{std::forward(e.value())}. \pnum \ensures @@ -7383,7 +7383,7 @@ \item \tcode{is_copy_constructible_v} is \tcode{true} and \item -\tcode{is_nothrow_move_constructible_v || is_nothrow_move_constructible_v} +\tcode{is_nothrow_move_constructible_v || is_nothrow_move_constructible_v} is \tcode{true}. \end{itemize} \end{itemdescr} @@ -7434,7 +7434,7 @@ \pnum \remarks -The exception specification is +The exception specification is equivalent to: \begin{codeblock} is_nothrow_move_assignable_v && is_nothrow_move_constructible_v && is_nothrow_move_assignable_v && is_nothrow_move_constructible_v @@ -7609,7 +7609,7 @@ \begin{floattable}{\tcode{swap(expected\&)} effects}{expected.object.swap} {lx{0.35\hsize}x{0.35\hsize}} \topline -& \chdr{\tcode{this->has_value()}} & \rhdr{\tcode{!has_value()}} \\ \capsep +& \chdr{\tcode{this->has_value()}} & \rhdr{\tcode{!this->has_value()}} \\ \capsep \lhdr{\tcode{rhs.has_value()}} & equivalent to: \tcode{using std::swap; swap(\exposid{val}, rhs.\exposid{val});} & calls \tcode{rhs.swap(*this)} \\ @@ -7654,7 +7654,7 @@ \pnum \remarks -The exception specification is: +The exception specification is equivalent to: \begin{codeblock} is_nothrow_move_constructible_v && is_nothrow_swappable_v && is_nothrow_move_constructible_v && is_nothrow_swappable_v @@ -7809,7 +7809,7 @@ \pnum \mandates \tcode{is_copy_constructible_v} is \tcode{true} and -\tcode{is_convertible} is \tcode{true}. +\tcode{is_convertible_v} is \tcode{true}. \pnum \returns @@ -7825,7 +7825,7 @@ \pnum \mandates \tcode{is_move_constructible_v} is \tcode{true} and -\tcode{is_convertible} is \tcode{true}. +\tcode{is_convertible_v} is \tcode{true}. \pnum \returns @@ -7855,7 +7855,7 @@ \indexlibrarymember{operator==}{expected}% \begin{itemdecl} -template constexpr bool operator==(const expected& x, const T2& v); +template friend constexpr bool operator==(const expected& x, const T2& v); \end{itemdecl} \begin{itemdescr} @@ -7874,7 +7874,7 @@ \indexlibrarymember{operator==}{expected}% \begin{itemdecl} -template constexpr bool operator==(const expected& x, const unexpected& e); +template friend constexpr bool operator==(const expected& x, const unexpected& e); \end{itemdecl} \begin{itemdescr} @@ -7938,7 +7938,7 @@ // \ref{expected.void.swap}, swap constexpr void swap(expected&) noexcept(@\seebelow@); - friend constexpr void swap(expected&, expected&) noexcept(@\seebelow@); + friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(x.swap(y))); // \ref{expected.void.obs}, observers constexpr explicit operator bool() const noexcept; @@ -8265,7 +8265,7 @@ \pnum \remarks -The exception specification is +The exception specification is equivalent to \tcode{is_nothrow_move_constructible_v \&\& is_nothrow_move_assignable_v}. \pnum @@ -8343,7 +8343,7 @@ \begin{floattable}{\tcode{swap(expected\&)} effects}{expected.void.swap} {lx{0.35\hsize}x{0.35\hsize}} \topline -& \chdr{\tcode{this->has_value()}} & \rhdr{\tcode{!has_value()}} \\ \capsep +& \chdr{\tcode{this->has_value()}} & \rhdr{\tcode{!this->has_value()}} \\ \capsep \lhdr{\tcode{rhs.has_value()}} & no effects & calls \tcode{rhs.swap(*this)} \\ @@ -8367,7 +8367,7 @@ \pnum \remarks -The exception specification is +The exception specification is equivalent to \tcode{is_nothrow_move_constructible_v \&\& is_nothrow_swappable_v}. \end{itemdescr}