diff --git a/source/support.tex b/source/support.tex index 95d674aafb..e32f47e448 100644 --- a/source/support.tex +++ b/source/support.tex @@ -682,7 +682,7 @@ #define @\defnlibxname{cpp_lib_freestanding_memory}@ 202502L // freestanding, also in \libheader{memory} #define @\defnlibxname{cpp_lib_freestanding_numeric}@ 202502L // freestanding, also in \libheader{numeric} #define @\defnlibxname{cpp_lib_freestanding_operator_new}@ @\seebelow@ // freestanding, also in \libheader{new} -#define @\defnlibxname{cpp_lib_freestanding_optional}@ 202311L // freestanding, also in \libheader{optional} +#define @\defnlibxname{cpp_lib_freestanding_optional}@ 202506L // freestanding, also in \libheader{optional} #define @\defnlibxname{cpp_lib_freestanding_random}@ 202502L // freestanding, also in \libheader{random} #define @\defnlibxname{cpp_lib_freestanding_ranges}@ 202306L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_freestanding_ratio}@ 202306L // freestanding, also in \libheader{ratio} @@ -752,7 +752,7 @@ // \libheader{string}, \libheader{unordered_map}, \libheader{unordered_set}, \libheader{vector} #define @\defnlibxname{cpp_lib_not_fn}@ 202306L // freestanding, also in \libheader{functional} #define @\defnlibxname{cpp_lib_null_iterators}@ 201304L // freestanding, also in \libheader{iterator} -#define @\defnlibxname{cpp_lib_optional}@ 202110L // also in \libheader{optional} +#define @\defnlibxname{cpp_lib_optional}@ 202506L // also in \libheader{optional} #define @\defnlibxname{cpp_lib_optional_range_support}@ 202406L // freestanding, also in \libheader{optional} #define @\defnlibxname{cpp_lib_out_ptr}@ 202311L // freestanding, also in \libheader{memory} #define @\defnlibxname{cpp_lib_parallel_algorithm}@ 201603L // also in \libheader{algorithm}, \libheader{numeric} diff --git a/source/utilities.tex b/source/utilities.tex index ced638f3f7..89e2000754 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -3196,15 +3196,21 @@ namespace std { // \ref{optional.optional}, class template \tcode{optional} template - class optional; // partially freestanding + class optional; // partially freestanding + + // \ref{optional.optional.ref}, partial specialization of \tcode{optional} for lvalue reference types + template + class optional; // partially freestanding template constexpr bool ranges::enable_view> = true; template constexpr auto format_kind> = range_format::disabled; + template + constexpr bool ranges::enable_borrowed_range> = true; template - concept @\defexposconcept{is-derived-from-optional}@ = requires(const T& t) { // \expos + concept @\defexposconceptnc{is-derived-from-optional}@ = requires(const T& t) { // \expos [](const optional&){ }(t); }; @@ -3379,9 +3385,14 @@ member \tcode{val} points to the contained value. \pnum -\tcode{T} shall be a type -other than \cv{} \tcode{in_place_t} or \cv{} \tcode{nullopt_t} -that meets the \oldconcept{Destructible} requirements (\tref{cpp17.destructible}). +A type \tcode{X} is a +\defnx{valid contained type}{valid contained type!\idxcode{optional}} for \tcode{optional} +if \tcode{X} is an lvalue reference type or a complete non-array object type, +and \tcode{remove_cvref_t} is a type other than \tcode{in_place_t} or \tcode{nullopt_t}. +If a specialization of \tcode{optional} is instantiated with a type \tcode{T} +that is not a valid contained type for \tcode{optional}, the program is ill-formed. +If \tcode{T} is an object type, +\tcode{T} shall meet the \oldconcept{Destructible} requirements (\tref{cpp17.destructible}). \rSec3[optional.ctor]{Constructors} @@ -3454,7 +3465,7 @@ \pnum \effects If \tcode{rhs} contains a value, direct-non-list-initializes the contained value -with \tcode{std::move(*rhs)}. +with \tcode{*std::move(rhs)}. \tcode{rhs.has_value()} is unchanged. \pnum @@ -3618,7 +3629,7 @@ \pnum \effects If \tcode{rhs} contains a value, -direct-non-list-initializes the contained value with \tcode{std::move(*rhs)}. +direct-non-list-initializes the contained value with \tcode{*std::move(rhs)}. \tcode{rhs.has_value()} is unchanged. \pnum @@ -3744,8 +3755,8 @@ {\tcode{*this} does not contain a value} \rowhdr{\tcode{rhs} contains a value} & -assigns \tcode{std::move(*rhs)} to the contained value & -direct-non-list-initializes the contained value with \tcode{std::move(*rhs)} \\ +assigns \tcode{*std::move(rhs)} to the contained value & +direct-non-list-initializes the contained value with \tcode{*std::move(rhs)} \\ \rowsep \rowhdr{\tcode{rhs} does not contain a value} & @@ -3894,8 +3905,8 @@ {\tcode{*this} does not contain a value} \rowhdr{\tcode{rhs} contains a value} & -assigns \tcode{std::move(*rhs)} to the contained value & -direct-non-list-initializes the contained value with \tcode{std::move(*rhs)} \\ +assigns \tcode{*std::move(rhs)} to the contained value & +direct-non-list-initializes the contained value with \tcode{*std::move(rhs)} \\ \rowsep \rowhdr{\tcode{rhs} does not contain a value} & @@ -4319,8 +4330,7 @@ \pnum \mandates -\tcode{U} is a non-array object type -other than \tcode{in_place_t} or \tcode{nullopt_t}. +\tcode{U} is a valid contained type for \tcode{optional}. The declaration \begin{codeblock} U u(invoke(std::forward(f), *@\exposid{val}@)); @@ -4351,8 +4361,7 @@ \pnum \mandates -\tcode{U} is a non-array object type -other than \tcode{in_place_t} or \tcode{nullopt_t}. +\tcode{U} is a valid contained type for \tcode{optional}. The declaration \begin{codeblock} U u(invoke(std::forward(f), std::move(*@\exposid{val}@))); @@ -4442,6 +4451,551 @@ \tcode{*this} does not contain a value. \end{itemdescr} +\rSec2[optional.optional.ref]{Partial specialization of \tcode{optional} for reference types} + +\rSec3[optional.optional.ref.general]{General} +\begin{codeblock} +namespace std { + template + class optional { + public: + using value_type = T; + using iterator = @\impdefnc@; // see~\ref{optional.ref.iterators} + + public: + // \ref{optional.ref.ctor}, constructors + constexpr optional() noexcept = default; + constexpr optional(nullopt_t) noexcept : optional() {} + constexpr optional(const optional& rhs) noexcept = default; + + template + constexpr explicit optional(in_place_t, Arg&& arg); + template + constexpr explicit(@\seebelow@) optional(U&& u) noexcept(@\seebelow@); + template + constexpr explicit(@\seebelow@) optional(optional& rhs) noexcept(@\seebelow@); + template + constexpr explicit(@\seebelow@) optional(const optional& rhs) noexcept(@\seebelow@); + template + constexpr explicit(@\seebelow@) optional(optional&& rhs) noexcept(@\seebelow@); + template + constexpr explicit(@\seebelow@) optional(const optional&& rhs) noexcept(@\seebelow@); + + constexpr ~optional() = default; + + // \ref{optional.ref.assign}, assignment + constexpr optional& operator=(nullopt_t) noexcept; + constexpr optional& operator=(const optional& rhs) noexcept = default; + + template constexpr T& emplace(U&& u) noexcept(@\seebelow@); + + // \ref{optional.ref.swap}, swap + constexpr void swap(optional& rhs) noexcept; + + // \ref{optional.iterators}, iterator support + constexpr iterator begin() const noexcept; + constexpr iterator end() const noexcept; + + // \ref{optional.ref.observe}, observers + 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; // freestanding-deleted + template> + constexpr remove_cv_t value_or(U&& u) const; + + // \ref{optional.ref.monadic}, monadic operations + template constexpr auto and_then(F&& f) const; + template constexpr optional> transform(F&& f) const; + template constexpr optional or_else(F&& f) const; + + // \ref{optional.ref.mod}, modifiers + constexpr void reset() noexcept; + + private: + T* @\exposidnc{val}@ = nullptr; // \expos + + // \ref{optional.ref.expos}, exposition only helper functions + template + constexpr void @\exposidnc{convert-ref-init-val}@(U&& u); // \expos + }; +} +\end{codeblock} + +\pnum +An object of \tcode{optional} +\defnx{contains a value}{contains a value!\idxcode{optional.ref}} +if and only if \tcode{\exposidnc{val} != nullptr} is \tcode{true}. +When an \tcode{optional} contains a value, +the \defnx{contained value}{contained value!\idxcode{optional.ref}} +is a reference to \tcode{*\exposid{val}}. + +\rSec3[optional.ref.ctor]{Constructors} + +\begin{itemdecl} +template + constexpr explicit optional(in_place_t, Arg&& arg); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item \tcode{is_constructible_v} is \tcode{true}, and +\item \tcode{reference_constructs_from_temporary_v} is \tcode{false}. +\end{itemize} + +\pnum +\effects +Equivalent to: \tcode{\exposid{convert-ref-init-val}(std::forward(arg))}. + +\pnum +\ensures +\tcode{*this} contains a value. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr explicit(!is_convertible_v) + optional(U&& u) noexcept(is_nothrow_constructible_v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item \tcode{is_same_v, optional>} is \tcode{false}, +\item \tcode{is_same_v, in_place_t>} is \tcode{false}, and +\item \tcode{is_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Equivalent to: \tcode{\exposid{convert-ref-init-val}(std::forward(u))}. + +\pnum +\ensures +\tcode{*this} contains a value. + +\pnum +\remarks + This constructor is defined as deleted if +\begin{codeblock} +reference_constructs_from_temporary_v +\end{codeblock} + is \tcode{true}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr explicit(!is_convertible_v) + optional(optional& rhs) noexcept(is_nothrow_constructible_v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item \tcode{is_same_v, optional>} is \tcode{false}, +\item \tcode{is_same_v} is \tcode{false}, and +\item \tcode{is_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Equivalent to: +\begin{codeblock} +if (rhs.has_value()) @\exposid{convert-ref-init-val}@(*rhs); +\end{codeblock} + +\pnum +\remarks +This constructor is defined as deleted if +\begin{codeblock} +reference_constructs_from_temporary_v +\end{codeblock} +is \tcode{true}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr explicit(!is_convertible_v) + optional(const optional& rhs) noexcept(is_nothrow_constructible_v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item \tcode{is_same_v, optional>} is \tcode{false}, +\item \tcode{is_same_v} is \tcode{false}, and +\item \tcode{is_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Equivalent to: +\begin{codeblock} +if (rhs.has_value()) @\exposid{convert-ref-init-val}@(*rhs); +\end{codeblock} + +\pnum +\remarks +This constructor is defined as deleted if +\begin{codeblock} +reference_constructs_from_temporary_v +\end{codeblock} +is \tcode{true}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr explicit(!is_convertible_v) + optional(optional&& rhs) noexcept(is_nothrow_constructible_v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item \tcode{is_same_v, optional>} is \tcode{false}, +\item \tcode{is_same_v} is \tcode{false}, and +\item \tcode{is_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Equivalent to: +\begin{codeblock} +if (rhs.has_value()) @\exposid{convert-ref-init-val}@(*std::move(rhs)); +\end{codeblock} + +\pnum +\remarks +This constructor is defined as deleted if +\begin{codeblock} +reference_constructs_from_temporary_v +\end{codeblock} +is \tcode{true}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr explicit(!is_convertible_v) + optional(const optional&& rhs) noexcept(is_nothrow_constructible_v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item \tcode{is_same_v, optional>} is \tcode{false}, and +\item \tcode{is_same_v} is \tcode{false}. +\item \tcode{is_constructible_v} is \tcode{true}, +\end{itemize} + +\pnum +\effects +Equivalent to: +\begin{codeblock} +if (rhs.has_value()) @\exposid{convert-ref-init-val}@(*std::move(rhs)); +\end{codeblock} + +\pnum +\remarks +This constructor is defined as deleted if +\begin{codeblock} +reference_constructs_from_temporary_v +\end{codeblock} +is \tcode{true}. +\end{itemdescr} + +\rSec3[optional.ref.assign]{Assignment} + +\begin{itemdecl} +constexpr optional& operator=(nullopt_t) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Assigns \tcode{nullptr} to \exposid{val}. + +\pnum +\ensures +\tcode{*this} does not contain a value. + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr T& emplace(U&& u) noexcept(is_nothrow_constructible_v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item \tcode{is_constructible_v} is \tcode{true}, and +\item \tcode{reference_constructs_from_temporary_v} is \tcode{false}. +\end{itemize} + +\pnum +\effects +Equivalent to: \tcode{\exposid{convert-ref-init-val}(std::forward(u))}. +\end{itemdescr} + +\rSec3[optional.ref.swap]{Swap} + +\begin{itemdecl} +constexpr void swap(optional& rhs) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{swap(\exposid{val}, rhs.\exposid{val})}. +\end{itemdescr} + +\rSec3[optional.ref.iterators]{Iterator support} + +\begin{itemdecl} +using iterator = @\impdef@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +This type +models \libconcept{contiguous_iterator}\iref{iterator.concept.contiguous}, +meets the \oldconcept{RandomAccessIterator} requirements\iref{random.access.iterators}, +and meets the requirements for constexpr iterators\iref{iterator.requirements.general}, +with value type \tcode{remove_cv_t}. +The reference type is \tcode{T\&} for \tcode{iterator}. + +\pnum +All requirements on container iterators\iref{container.reqmts} apply to +\tcode{optional::iterator}. +\end{itemdescr} + +\begin{itemdecl} +constexpr iterator begin() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns + If \tcode{has_value()} is \tcode{true}, + an iterator referring to \tcode{*\exposid{val}}. + Otherwise, a past-the-end iterator value. +\end{itemdescr} + +\begin{itemdecl} +constexpr iterator end() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{begin() + has_value()}. +\end{itemdescr} + +\rSec3[optional.ref.observe]{Observers} + +\begin{itemdecl} +constexpr T* operator->() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\hardexpects +\tcode{has_value()} is \tcode{true}. + +\pnum +\returns +\exposid{val}. + +\end{itemdescr} + +\begin{itemdecl} +constexpr T& operator*() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\hardexpects +\tcode{has_value()} is \tcode{true}. + +\pnum +\returns +\tcode{*\exposid{val}}. +\end{itemdescr} + +\begin{itemdecl} +constexpr explicit operator bool() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{\exposid{val} != nullptr}. +\end{itemdescr} + +\begin{itemdecl} +constexpr bool has_value() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{\exposid{val} != nullptr}. +\end{itemdescr} + +\begin{itemdecl} +constexpr T& value() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return has_value() ? *@\exposid{val}@ : throw bad_optional_access(); +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +template> constexpr remove_cv_t value_or(U&& u) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum + Let \tcode{X} be \tcode{remove_cv_t}. + +\pnum +\mandates +\tcode{is_constructible_v \&\& is_convertible_v} is \tcode{true}. + +\pnum +\effects + Equivalent to: +\begin{codeblock} +return has_value() ? *@\exposid{val}@ : static_cast(std::forward(u)); +\end{codeblock} +\end{itemdescr} + +\rSec3[optional.ref.monadic]{Monadic operations} + +\begin{itemdecl} +template constexpr auto and_then(F&& f) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{U} be \tcode{invoke_result_t}. + +\pnum +\mandates +\tcode{remove_cvref_t} is a specialization of \tcode{optional}. + +\pnum +\effects + Equivalent to: +\begin{codeblock} +if (has_value()) { + return invoke(std::forward(f), *@\exposid{val}@); +} else { + return remove_cvref_t(); +} +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +template + constexpr optional>> transform(F&& f) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum + Let \tcode{U} be \tcode{remove_cv_t>}. + +\pnum +\mandates +The declaration +\begin{codeblock} +U u(invoke(std::forward(f), *@\exposid{val}@)); +\end{codeblock} +is well-formed for some invented variable \tcode{u}. +\begin{note} +There is no requirement that \tcode{U} is movable\iref{dcl.init.general}. +\end{note} + +\pnum +\returns +If \tcode{*this} contains a value, an \tcode{optional} object +whose contained value is direct-non-list-initialized with +\tcode{invoke(std::forward(f), *\exposid{val})}; +otherwise, \tcode{optional()}. +\end{itemdescr} + +\begin{itemdecl} +template constexpr optional or_else(F&& f) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{F} models \tcode{\libconcept{invocable}}. + +\pnum +\mandates +\tcode{is_same_v>, optional>} is \tcode{true}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +if (has_value()) { + return *@\exposid{val}@; +} else { + return std::forward(f)(); +} +\end{codeblock} +\end{itemdescr} + +\rSec3[optional.ref.mod]{Modifiers} + +\begin{itemdecl} +constexpr void reset() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Assigns \tcode{nullptr} to \exposid{val}. + +\pnum +\ensures +\tcode{*this} does not contain a value. +\end{itemdescr} + +\rSec3[optional.ref.expos]{Exposition only helper functions} + +\begin{itemdecl} +template + constexpr void @\exposid{convert-ref-init-val}@(U&& u); // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Creates a variable \tcode{r} as if by \tcode{T\& r(std::forward(u));} +and then initializes \exposid{val} with \tcode{addressof(r)}. +\end{itemdescr} + \rSec2[optional.nullopt]{No-value state indicator} \indexlibraryglobal{nullopt_t}% @@ -4911,8 +5465,10 @@ \begin{itemdescr} \pnum \constraints -\tcode{is_move_constructible_v} is \tcode{true} and -\tcode{is_swappable_v} is \tcode{true}. +\begin{codeblock} +is_reference_v || (is_move_constructible_v && is_swappable_v) +\end{codeblock} +is \tcode{true}. \pnum \effects @@ -4925,6 +5481,12 @@ \end{itemdecl} \begin{itemdescr} +\pnum +\constraints +The call to \tcode{make_optional} does not use +an explicit \grammarterm{template-argument-list} that +begins with a type \grammarterm{template-argument}. + \pnum \returns \tcode{optional>(std::forward(v))}.