From 34369eb3982a00888c09fe8e3e40f1d705215e2f Mon Sep 17 00:00:00 2001 From: Steve Downey Date: Sat, 11 Jan 2025 23:13:35 +0000 Subject: [PATCH 1/9] Make base.pdf compile --- papers/P2988/base-optional.tex | 2 -- 1 file changed, 2 deletions(-) diff --git a/papers/P2988/base-optional.tex b/papers/P2988/base-optional.tex index 2871fd7f..8ab9c6b2 100644 --- a/papers/P2988/base-optional.tex +++ b/papers/P2988/base-optional.tex @@ -1,5 +1,3 @@ -\rSec0[utilities]{General utilities library} - \rSec1[optional]{Optional objects} \rSec2[optional.general]{General} From d01f4eab6ed0bb9efbc62e3ab81991ca423a17e3 Mon Sep 17 00:00:00 2001 From: Steve Downey Date: Sat, 11 Jan 2025 23:13:50 +0000 Subject: [PATCH 2/9] add Beman to bibliography --- papers/P2988/mybiblio.bib | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/papers/P2988/mybiblio.bib b/papers/P2988/mybiblio.bib index aeeb9fb3..7c14e99a 100644 --- a/papers/P2988/mybiblio.bib +++ b/papers/P2988/mybiblio.bib @@ -58,3 +58,12 @@ @misc{rawgithu58:online year = {}, note = {(Accessed on 08/14/2024)} } + +@misc{The_Beman_Project_beman_optional26, +author = {The Beman Project}, +license = {Apache-2.0}, +title = {{beman.optional26}}, +howpublished = {\url{https://github.com/bemanproject/optional26}}, +month = {}, +year = {}, +} \ No newline at end of file From 28588cfdf1d4ba0113ef29aa0f9dc86d5b2c918e Mon Sep 17 00:00:00 2001 From: Steve Downey Date: Sat, 11 Jan 2025 23:14:14 +0000 Subject: [PATCH 3/9] Add new constructors and assignments and reorder Fix the construction and assignment of optional&& to an optional where the referred to value could be stolen. --- include/beman/optional26/optional.hpp | 106 ++-- papers/P2988/new-optional.tex | 693 ++++++++++++++++++++++++++ 2 files changed, 726 insertions(+), 73 deletions(-) diff --git a/include/beman/optional26/optional.hpp b/include/beman/optional26/optional.hpp index cca8806c..1fe04b60 100644 --- a/include/beman/optional26/optional.hpp +++ b/include/beman/optional26/optional.hpp @@ -201,12 +201,16 @@ concept enable_forward_value = !std::is_same_v, optional> && !std::is_same_v, in_place_t> && std::is_constructible_v; template -concept enable_from_other = - !std::is_same_v && std::is_constructible_v && !std::is_constructible_v&> && - !std::is_constructible_v&&> && !std::is_constructible_v&> && - !std::is_constructible_v&&> && !std::is_convertible_v&, T> && - !std::is_convertible_v&&, T> && !std::is_convertible_v&, T> && - !std::is_convertible_v&&, T>; +concept enable_from_other = !std::is_same_v && // + std::is_constructible_v && // + !std::is_constructible_v&> && // + !std::is_constructible_v&&> && // + !std::is_constructible_v&> && // + !std::is_constructible_v&&> && // + !std::is_convertible_v&, T> && // + !std::is_convertible_v&&, T> && // + !std::is_convertible_v&, T> && // + !std::is_convertible_v&&, T>; template concept enable_assign_forward = !std::is_same_v, std::decay_t> && @@ -276,29 +280,15 @@ class optional { template constexpr explicit(!std::is_convertible_v) optional(const optional& rhs) - requires(!std::is_reference_v && detail::enable_from_other && - std::is_convertible_v); - - template - constexpr explicit(!std::is_convertible_v) optional(const optional& rhs) - requires(!std::is_reference_v && detail::enable_from_other && - !std::is_convertible_v); - - template - constexpr explicit(!std::is_convertible_v) optional(optional&& rhs) - requires(!std::is_reference_v && detail::enable_from_other && std::is_convertible_v); - - template - constexpr explicit(!std::is_convertible_v) optional(optional&& rhs) - requires(!std::is_reference_v && detail::enable_from_other && !std::is_convertible_v); + requires(!std::is_reference_v && detail::enable_from_other); template constexpr explicit(!std::is_convertible_v) optional(const optional& rhs) - requires(detail::enable_from_other && std::is_convertible_v); + requires(detail::enable_from_other); template - constexpr explicit(!std::is_convertible_v) optional(const optional& rhs) - requires(detail::enable_from_other && !std::is_convertible_v); + constexpr explicit(!std::is_convertible_v) optional(optional&& rhs) + requires(!std::is_reference_v && detail::enable_from_other); // \ref{optional.dtor}, destructor constexpr ~optional() @@ -470,26 +460,25 @@ inline constexpr optional::optional(in_place_t, std::initializer_list il, template template inline constexpr optional::optional(U&& u) - requires detail::enable_forward_value //&& std::is_convertible_v + requires detail::enable_forward_value : optional(in_place, std::forward(u)) {} /// Converting copy constructor. template template inline constexpr optional::optional(const optional& rhs) - requires(!std::is_reference_v && detail::enable_from_other && - std::is_convertible_v) + requires(!std::is_reference_v && detail::enable_from_other) { if (rhs.has_value()) { construct(*rhs); } } +/// Converting copy constructor for U& template template -inline constexpr optional::optional(const optional& rhs) - requires(!std::is_reference_v && detail::enable_from_other && - !std::is_convertible_v) +inline constexpr optional::optional(const optional& rhs) + requires(detail::enable_from_other) { if (rhs.has_value()) { construct(*rhs); @@ -500,43 +489,13 @@ inline constexpr optional::optional(const optional& rhs) template template inline constexpr optional::optional(optional&& rhs) - requires(!std::is_reference_v && detail::enable_from_other && std::is_convertible_v) + requires(!std::is_reference_v && detail::enable_from_other) { if (rhs.has_value()) { construct(std::move(*rhs)); } } -template -template -inline constexpr optional::optional(optional&& rhs) - requires(!std::is_reference_v && detail::enable_from_other && !std::is_convertible_v) -{ - if (rhs.has_value()) { - construct(std::move(*rhs)); - } -} - -template -template -inline constexpr optional::optional(const optional& rhs) - requires(detail::enable_from_other && std::is_convertible_v) -{ - if (rhs.has_value()) { - construct(*rhs); - } -} - -template -template -inline constexpr optional::optional(const optional& rhs) - requires(detail::enable_from_other && !std::is_convertible_v) -{ - if (rhs.has_value()) { - construct(*rhs); - } -} - // 22.5.3.3 Destructor[optional.dtor] template @@ -624,50 +583,51 @@ inline constexpr optional& optional::operator=(const optional& rhs) return *this; } -/// Converting move assignment operator. -/// -/// Moves the value from `rhs` if there is one. Otherwise resets the stored -/// value in `*this`. template template -inline constexpr optional& optional::operator=(optional&& rhs) - requires(!std::is_reference_v && detail::enable_assign_from_other) +inline constexpr optional& optional::operator=(const optional& rhs) + requires(detail::enable_assign_from_other) { if (has_value()) { if (rhs.has_value()) { - value_ = std::move(*rhs); + value_ = *rhs; } else { hard_reset(); } } else if (rhs.has_value()) { - construct(std::move(*rhs)); + construct(*rhs); } return *this; } +/// Converting move assignment operator. +/// +/// Moves the value from `rhs` if there is one. Otherwise resets the stored +/// value in `*this`. template template -inline constexpr optional& optional::operator=(const optional& rhs) - requires(detail::enable_assign_from_other) +inline constexpr optional& optional::operator=(optional&& rhs) + requires(!std::is_reference_v && detail::enable_assign_from_other) { if (has_value()) { if (rhs.has_value()) { - value_ = *rhs; + value_ = std::move(*rhs); } else { hard_reset(); } } else if (rhs.has_value()) { - construct(*rhs); + construct(std::move(*rhs)); } return *this; } + /// Constructs the value in-place, destroying the current one if there is /// one. template diff --git a/papers/P2988/new-optional.tex b/papers/P2988/new-optional.tex index 975d43bc..3a8d608d 100644 --- a/papers/P2988/new-optional.tex +++ b/papers/P2988/new-optional.tex @@ -133,6 +133,14 @@ constexpr explicit(@\seebelow@) optional(U&&); template constexpr explicit(@\seebelow@) optional(const optional&); +\end{codeblock} +\color{addclr} +\begin{codeblock} + template + constexpr explicit(@\seebelow@) optional(const optional&); +\end{codeblock} +\color{black} +\begin{codeblock} template constexpr explicit(@\seebelow@) optional(optional&&); @@ -145,6 +153,13 @@ constexpr optional& operator=(optional&&) noexcept(@\seebelow@); template constexpr optional& operator=(U&&); template constexpr optional& operator=(const optional&); +\end{codeblock} +\color{addclr} +\begin{codeblock} + template constexpr optional& operator=(const optional&); +\end{codeblock} +\color{black} +\begin{codeblock} template constexpr optional& operator=(optional&&); template constexpr T& emplace(Args&&...); template constexpr T& emplace(initializer_list, Args&&...); @@ -229,11 +244,689 @@ \rSec3[optional.ctor]{Constructors} +\pnum +The exposition-only variable template \exposid{converts-from-any-cvref} +is used by some constructors for \tcode{optional}. +\begin{codeblock} +template +constexpr bool @\exposid{converts-from-any-cvref}@ = // \expos + disjunction_v, is_convertible, + is_constructible, is_convertible, + is_constructible, is_convertible, + is_constructible, is_convertible>; +\end{codeblock} + +\indexlibraryctor{optional}% +\begin{itemdecl} +constexpr optional() noexcept; +constexpr optional(nullopt_t) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ensures +\tcode{*this} does not contain a value. + +\pnum +\remarks +No contained value is initialized. +For every object type \tcode{T} these constructors are constexpr constructors\iref{dcl.constexpr}. +\end{itemdescr} + +\indexlibraryctor{optional}% +\begin{itemdecl} +constexpr optional(const optional& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +If \tcode{rhs} contains a value, direct-non-list-initializes the contained value +with \tcode{*rhs}. + +\pnum +\ensures +\tcode{rhs.has_value() == this->has_value()}. + +\pnum +\throws +Any exception thrown by the selected constructor of \tcode{T}. + +\pnum +\remarks +This constructor is defined as deleted unless +\tcode{is_copy_constructible_v} is \tcode{true}. +If \tcode{is_trivially_copy_constructible_v} is \tcode{true}, +this constructor is trivial. +\end{itemdescr} + +\indexlibraryctor{optional}% +\begin{itemdecl} +constexpr optional(optional&& rhs) noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_move_constructible_v} is \tcode{true}. + +\pnum +\effects +If \tcode{rhs} contains a value, direct-non-list-initializes the contained value +with \tcode{std::move(*rhs)}. +\tcode{rhs.has_value()} is unchanged. + +\pnum +\ensures +\tcode{rhs.has_value() == this->has_value()}. + +\pnum +\throws +Any exception thrown by the selected constructor of \tcode{T}. + +\pnum +\remarks +The exception specification is equivalent to +\tcode{is_nothrow_move_constructible_v}. +If \tcode{is_trivially_move_constructible_v} is \tcode{true}, +this constructor is trivial. +\end{itemdescr} + +\indexlibraryctor{optional}% +\begin{itemdecl} +template constexpr explicit optional(in_place_t, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\effects +Direct-non-list-initializes the contained value with \tcode{std::forward(args)...}. + +\pnum +\ensures +\tcode{*this} contains a value. + +\pnum +\throws +Any exception thrown by the selected constructor of \tcode{T}. + +\pnum +\remarks +If \tcode{T}'s constructor selected for the initialization is a constexpr constructor, this constructor is a constexpr constructor. +\end{itemdescr} + +\indexlibraryctor{optional}% +\begin{itemdecl} +template + constexpr explicit optional(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 the contained value with \tcode{il, std::forward(args)...}. + +\pnum +\ensures +\tcode{*this} contains a value. + +\pnum +\throws +Any exception thrown by the selected constructor of \tcode{T}. + +\pnum +\remarks +If \tcode{T}'s constructor selected for the initialization is a constexpr constructor, this constructor is a constexpr constructor. +\end{itemdescr} + +\indexlibraryctor{optional}% +\begin{itemdecl} +template constexpr explicit(@\seebelow@) optional(U&& v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item \tcode{is_constructible_v} is \tcode{true}, +\item \tcode{is_same_v, in_place_t>} is \tcode{false}, +\item \tcode{is_same_v, optional>} is \tcode{false}, and +\item if \tcode{T} is \cv{} \tcode{bool}, +\tcode{remove_cvref_t} is not a specialization of \tcode{optional}. +\end{itemize} + +\pnum +\effects +Direct-non-list-initializes the contained value with \tcode{std::forward(v)}. + +\pnum +\ensures +\tcode{*this} contains a value. + +\pnum +\throws +Any exception thrown by the selected constructor of \tcode{T}. + +\pnum +\remarks +If \tcode{T}'s selected constructor is a constexpr constructor, +this constructor is a constexpr constructor. +The expression inside \keyword{explicit} is equivalent to: +\begin{codeblock} +!is_convertible_v +\end{codeblock} +\end{itemdescr} + +\indexlibraryctor{optional}% +\begin{itemdecl} +template constexpr explicit(@\seebelow@) optional(const optional& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item \tcode{is_constructible_v} is \tcode{true}, and +\item if \tcode{T} is not \cv{} \tcode{bool}, +\tcode{\exposid{converts-from-any-cvref}>} is \tcode{false}. +\end{itemize} + +\pnum +\effects +If \tcode{rhs} contains a value, direct-non-list-initializes the contained value with \tcode{*rhs}. + +\pnum +\ensures +\tcode{rhs.has_value() == this->has_value()}. + +\pnum +\throws +Any exception thrown by the selected constructor of \tcode{T}. + +\pnum +\remarks +The expression inside \keyword{explicit} is equivalent to: +\begin{codeblock} +!is_convertible_v +\end{codeblock} +\end{itemdescr} + +\begin{addedblock} +\indexlibraryctor{optional}% +\begin{itemdecl} +template constexpr explicit(@\seebelow@) optional(const optional& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item \tcode{is_constructible_v} is \tcode{true}, and +\item if \tcode{T} is not \cv{} \tcode{bool}, +\tcode{\exposid{converts-from-any-cvref}>} is \tcode{false}. +\end{itemize} + +\pnum +\effects +If \tcode{rhs} contains a value, direct-non-list-initializes the contained value with \tcode{*rhs}. + +\pnum +\ensures +\tcode{rhs.has_value() == this->has_value()}. + +\pnum +\throws +Any exception thrown by the selected constructor of \tcode{T}. + +\pnum +\remarks +The expression inside \keyword{explicit} is equivalent to: +\begin{codeblock} +!is_convertible_v +\end{codeblock} +\end{itemdescr} +\end{addedblock} + +\indexlibraryctor{optional}% +\begin{itemdecl} +template constexpr explicit(@\seebelow@) optional(optional&& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\begin{addedblock} +\item \tcode{is_reference_v} is \tcode{false}, +\end{addedblock} +\item \tcode{is_constructible_v} is \tcode{true}, and +\item if \tcode{T} is not \cv{} \tcode{bool}, +\tcode{\exposid{converts-from-any-cvref}>} is \tcode{false}. +\end{itemize} + +\pnum +\effects +If \tcode{rhs} contains a value, +direct-non-list-initializes the contained value with \tcode{std::move(*rhs)}. +\tcode{rhs.has_value()} is unchanged. + +\pnum +\ensures +\tcode{rhs.has_value() == this->has_value()}. + +\pnum +\throws +Any exception thrown by the selected constructor of \tcode{T}. + +\pnum +\remarks +The expression inside \keyword{explicit} is equivalent to: +\begin{codeblock} +!is_convertible_v +\end{codeblock} +\end{itemdescr} \rSec3[optional.dtor]{Destructor} \rSec3[optional.assign]{Assignment} +\indexlibrarymember{operator=}{optional}% +\begin{itemdecl} +constexpr optional& operator=(nullopt_t) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +If \tcode{*this} contains a value, calls \tcode{val->T::\~T()} to destroy the contained value; otherwise no effect. + +\pnum +\ensures +\tcode{*this} does not contain a value. + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + +\indexlibrarymember{operator=}{optional}% +\begin{itemdecl} +constexpr optional& operator=(const optional& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +See \tref{optional.assign.copy}. +\begin{lib2dtab2}{\tcode{optional::operator=(const optional\&)} effects}{optional.assign.copy} +{\tcode{*this} contains a value} +{\tcode{*this} does not contain a value} + +\rowhdr{\tcode{rhs} contains a value} & +assigns \tcode{*rhs} to the contained value & +direct-non-list-initializes the contained value with \tcode{*rhs} \\ +\rowsep + +\rowhdr{\tcode{rhs} does not contain a value} & +destroys the contained value by calling \tcode{val->T::\~T()} & +no effect \\ +\end{lib2dtab2} + +\pnum +\ensures +\tcode{rhs.has_value() == this->has_value()}. + +\pnum +\returns +\tcode{*this}. + +\pnum +\remarks +If any exception is thrown, the result of the expression \tcode{this->has_value()} remains unchanged. +If an exception is thrown during the call to \tcode{T}'s copy constructor, no effect. +If an exception is thrown during the call to \tcode{T}'s copy assignment, +the state of its contained value is as defined by the exception safety guarantee of \tcode{T}'s copy assignment. +This operator is defined as deleted unless +\tcode{is_copy_constructible_v} is \tcode{true} and +\tcode{is_copy_assignable_v} is \tcode{true}. +If \tcode{is_trivially_copy_constructible_v \&\&} +\tcode{is_trivially_copy_assignable_v \&\&} +\tcode{is_trivially_destructible_v} is \tcode{true}, +this assignment operator is trivial. +\end{itemdescr} + +\indexlibrarymember{operator=}{optional}% +\begin{itemdecl} +constexpr optional& operator=(optional&& rhs) noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_move_constructible_v} is \tcode{true} and +\tcode{is_move_assignable_v} is \tcode{true}. + +\pnum +\effects +See \tref{optional.assign.move}. +The result of the expression \tcode{rhs.has_value()} remains unchanged. +\begin{lib2dtab2}{\tcode{optional::operator=(optional\&\&)} effects}{optional.assign.move} +{\tcode{*this} contains a value} +{\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)} \\ +\rowsep + +\rowhdr{\tcode{rhs} does not contain a value} & +destroys the contained value by calling \tcode{val->T::\~T()} & +no effect \\ +\end{lib2dtab2} + +\pnum +\ensures +\tcode{rhs.has_value() == this->has_value()}. + +\pnum +\returns +\tcode{*this}. + +\pnum +\remarks +The exception specification is equivalent to: +\begin{codeblock} +is_nothrow_move_assignable_v && is_nothrow_move_constructible_v +\end{codeblock} + +\pnum +If any exception is thrown, the result of the expression \tcode{this->has_value()} remains unchanged. +If an exception is thrown during the call to \tcode{T}'s move constructor, +the state of \tcode{*rhs.val} is determined by the exception safety guarantee of \tcode{T}'s move constructor. +If an exception is thrown during the call to \tcode{T}'s move assignment, +the state of \tcode{*val} and \tcode{*rhs.val} is determined by the exception safety guarantee of \tcode{T}'s move assignment. +If \tcode{is_trivially_move_constructible_v \&\&} +\tcode{is_trivially_move_assignable_v \&\&} +\tcode{is_trivially_destructible_v} is \tcode{true}, +this assignment operator is trivial. +\end{itemdescr} + +\indexlibrarymember{operator=}{optional}% +\begin{itemdecl} +template constexpr optional& operator=(U&& v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_same_v, optional>} is \tcode{false}, +\tcode{conjunction_v, is_same>>} is \tcode{false}, +\tcode{is_constructible_v} is \tcode{true}, and +\tcode{is_assignable_v} is \tcode{true}. + +\pnum +\effects +If \tcode{*this} contains a value, assigns \tcode{std::forward(v)} to the contained value; otherwise direct-non-list-initializes the contained value with \tcode{std::forward(v)}. + +\pnum +\ensures +\tcode{*this} contains a value. + +\pnum +\returns +\tcode{*this}. + +\pnum +\remarks +If any exception is thrown, the result of the expression \tcode{this->has_value()} remains unchanged. If an exception is thrown during the call to \tcode{T}'s constructor, the state of \tcode{v} is determined by the exception safety guarantee of \tcode{T}'s constructor. If an exception is thrown during the call to \tcode{T}'s assignment, the state of \tcode{*val} and \tcode{v} is determined by the exception safety guarantee of \tcode{T}'s assignment. +\end{itemdescr} + +\indexlibrarymember{operator=}{optional}% +\begin{itemdecl} +template constexpr optional& operator=(const optional& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\begin{addedblock} +\item \tcode{is_reference_v} is \tcode{false}, +\end{addedblock} +\item \tcode{is_constructible_v} is \tcode{true}, +\item \tcode{is_assignable_v} is \tcode{true}, +\item \tcode{\exposid{converts-from-any-cvref}>} is \tcode{false}, +\item \tcode{is_assignable_v\&>} is \tcode{false}, +\item \tcode{is_assignable_v\&\&>} is \tcode{false}, +\item \tcode{is_assignable_v\&>} is \tcode{false}, and +\item \tcode{is_assignable_v\&\&>} is \tcode{false}. +\end{itemize} + +\pnum +\effects +See \tref{optional.assign.copy.templ}. +\begin{lib2dtab2}{\tcode{optional::operator=(const optional\&)} effects}{optional.assign.copy.templ} +{\tcode{*this} contains a value} +{\tcode{*this} does not contain a value} + +\rowhdr{\tcode{rhs} contains a value} & +assigns \tcode{*rhs} to the contained value & +direct-non-list-initializes the contained value with \tcode{*rhs} \\ +\rowsep + +\rowhdr{\tcode{rhs} does not contain a value} & +destroys the contained value by calling \tcode{val->T::\~T()} & +no effect \\ +\end{lib2dtab2} + +\pnum +\ensures +\tcode{rhs.has_value() == this->has_value()}. + +\pnum +\returns +\tcode{*this}. + +\pnum +\remarks +If any exception is thrown, +the result of the expression \tcode{this->has_value()} remains unchanged. +If an exception is thrown during the call to \tcode{T}'s constructor, +the state of \tcode{*rhs.val} is determined by +the exception safety guarantee of \tcode{T}'s constructor. +If an exception is thrown during the call to \tcode{T}'s assignment, +the state of \tcode{*val} and \tcode{*rhs.val} is determined by +the exception safety guarantee of \tcode{T}'s assignment. +\end{itemdescr} + +\begin{addedblock} +\indexlibrarymember{operator=}{optional}% +\begin{itemdecl} +template constexpr optional& operator=(const optional& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item \tcode{is_constructible_v} is \tcode{true}, +\item \tcode{is_assignable_v} is \tcode{true}, +\item \tcode{\exposid{converts-from-any-cvref}>} is \tcode{false}, +\item \tcode{is_assignable_v\&>} is \tcode{false}, +\item \tcode{is_assignable_v\&\&>} is \tcode{false}, +\item \tcode{is_assignable_v\&>} is \tcode{false}, and +\item \tcode{is_assignable_v\&\&>} is \tcode{false}. +\end{itemize} + +\pnum +\effects +See \tref{optional.assign.refcopy.templ}. +\begin{lib2dtab2}{\tcode{optional::operator=(const optional\&)} effects}{optional.assign.refcopy.templ} +{\tcode{*this} contains a value} +{\tcode{*this} does not contain a value} + +\rowhdr{\tcode{rhs} contains a value} & +assigns \tcode{*rhs} to the contained value & +direct-non-list-initializes the contained value with \tcode{*rhs} \\ +\rowsep + +\rowhdr{\tcode{rhs} does not contain a value} & +destroys the contained value by calling \tcode{val->T::\~T()} & +no effect \\ +\end{lib2dtab2} + +\pnum +\ensures +\tcode{rhs.has_value() == this->has_value()}. + +\pnum +\returns +\tcode{*this}. + +\pnum +\remarks +If any exception is thrown, +the result of the expression \tcode{this->has_value()} remains unchanged. +If an exception is thrown during the call to \tcode{T}'s constructor, +the state of \tcode{*rhs.val} is determined by +the exception safety guarantee of \tcode{T}'s constructor. +If an exception is thrown during the call to \tcode{T}'s assignment, +the state of \tcode{*val} and \tcode{*rhs.val} is determined by +the exception safety guarantee of \tcode{T}'s assignment. +\end{itemdescr} +\end{addedblock} + +\indexlibrarymember{operator=}{optional}% +\begin{itemdecl} +template constexpr optional& operator=(optional&& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\begin{addedblock} +\item \tcode{is_reference_v} is \tcode{false}, +\end{addedblock} +\item \tcode{is_constructible_v} is \tcode{true}, +\item \tcode{is_assignable_v} is \tcode{true}, +\item \tcode{\exposid{converts-from-any-cvref}>} is \tcode{false}, +\item \tcode{is_assignable_v\&>} is \tcode{false}, +\item \tcode{is_assignable_v\&\&>} is \tcode{false}, +\item \tcode{is_assignable_v\&>} is \tcode{false}, and +\item \tcode{is_assignable_v\&\&>} is \tcode{false}. +\end{itemize} + +\pnum +\effects +See \tref{optional.assign.move.templ}. +The result of the expression \tcode{rhs.has_value()} remains unchanged. +\begin{lib2dtab2}{\tcode{optional::operator=(optional\&\&)} effects}{optional.assign.move.templ} +{\tcode{*this} contains a value} +{\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)} \\ +\rowsep + +\rowhdr{\tcode{rhs} does not contain a value} & +destroys the contained value by calling \tcode{val->T::\~T()} & +no effect \\ +\end{lib2dtab2} + +\pnum +\ensures +\tcode{rhs.has_value() == this->has_value()}. + +\pnum +\returns +\tcode{*this}. + +\pnum +\remarks +If any exception is thrown, +the result of the expression \tcode{this->has_value()} remains unchanged. +If an exception is thrown during the call to \tcode{T}'s constructor, +the state of \tcode{*rhs.val} is determined by +the exception safety guarantee of \tcode{T}'s constructor. +If an exception is thrown during the call to \tcode{T}'s assignment, +the state of \tcode{*val} and \tcode{*rhs.val} is determined by +the exception safety guarantee of \tcode{T}'s assignment. +\end{itemdescr} + +\indexlibrarymember{emplace}{optional}% +\begin{itemdecl} +template constexpr T& emplace(Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\effects +Calls \tcode{*this = nullopt}. Then direct-non-list-initializes the contained value +with \tcode{std::forward\brk{}(args)...}. + +\pnum +\ensures +\tcode{*this} contains a value. + +\pnum +\returns +A reference to the new contained value. + +\pnum +\throws +Any exception thrown by the selected constructor of \tcode{T}. + +\pnum +\remarks +If an exception is thrown during the call to \tcode{T}'s constructor, \tcode{*this} does not contain a value, and the previous \tcode{*val} (if any) has been destroyed. +\end{itemdescr} + +\indexlibrarymember{emplace}{optional}% +\begin{itemdecl} +template constexpr T& emplace(initializer_list il, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v\&, Args...>} is \tcode{true}. + +\pnum +\effects +Calls \tcode{*this = nullopt}. Then direct-non-list-initializes the contained value with +\tcode{il, std::\brk{}forward(args)...}. + +\pnum +\ensures +\tcode{*this} contains a value. + +\pnum +\returns +A reference to the new contained value. + +\pnum +\throws +Any exception thrown by the selected constructor of \tcode{T}. + +\pnum +\remarks +If an exception is thrown during the call to \tcode{T}'s constructor, \tcode{*this} does not contain a value, and the previous \tcode{*val} (if any) has been destroyed. +\end{itemdescr} + \rSec3[optional.swap]{Swap} From 41ac3b7939718ef0b48a92e2451b114096de2fdf Mon Sep 17 00:00:00 2001 From: Steve Downey Date: Sat, 11 Jan 2025 23:15:44 +0000 Subject: [PATCH 4/9] Update verbiage around wording --- papers/P2988/optional_ref_wording.tex | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/papers/P2988/optional_ref_wording.tex b/papers/P2988/optional_ref_wording.tex index 0ec137f0..7a8b95e0 100644 --- a/papers/P2988/optional_ref_wording.tex +++ b/papers/P2988/optional_ref_wording.tex @@ -18,7 +18,7 @@ \begin{flushright} \begin{tabular}{ll} - Document \#: & P2988R8 \\ + Document \#: & P2988R9 \\ Date: & \today \\ Project: & Programming Language C++ \\ Audience: & LEWG @@ -36,6 +36,10 @@ \chapter*{Changes Since Last Version} \begin{itemize} +\item \textbf{Changes since R8} + \begin{itemize} + \item Fix move/assign optional allowing stealing of referenced U + \end{itemize} \item \textbf{Changes since R7} \begin{itemize} \item Wording mandates/constraint fixes @@ -384,6 +388,9 @@ \section{Assignment of optional} This observation allows us to provide only copy-assignment for \tcode{optional}, instead of a set of converting assignments, that would need to replicate the signatures of constructors and their constraints. Assignment from any other value is handled by first implicitly constructing \tcode{optional} and then using copy-assignment. Move-assignment is the same as copy-assignment, since only pointer copy is involved. +\section{Copy and Assignment of optional\&\& to optional} +Care must be take to prevent the assignment of a movable optional to disallow the copy or assignment of the underlying referred to value to be stolen. The \tcode{optional const\&} assignment or copy constructor should be used instead. We thank Jan Kokemüller for uncovering this bug. + \chapter{Proposal} @@ -406,6 +413,10 @@ \chapter{Impact on the standard} The proposed changes are relative to the current working draft \cite{N4910}. +\chapter{Acknowledgements} +Many thanks to all of the reviewers and authors of beman/optional26, \cite{The_Beman_Project_beman_optional26}, in particular A. Jiang, Darius Neațu, David Sankel, Eddie Nolan, Jan Kokemüller, Jeff Garland, and River. Tomasz Kamiński provided extensive support for the library wording of optional. + + \chapter*{Document history} \begin{itemize} From 5637421bde4b1db2a723450e69d5bef2d6aa7074 Mon Sep 17 00:00:00 2001 From: Steve Downey Date: Sat, 11 Jan 2025 23:26:06 +0000 Subject: [PATCH 5/9] Improve parallelism in implementation Improve the parallelism in t he declarations in the implementation to clarify that the difference in the overloads is due to the 'Other' parameter for removing it from consideration for overload since the U parameter is *already* a reference. Checking for 'const U&' is no longer the right thing to check. --- include/beman/optional26/optional.hpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/include/beman/optional26/optional.hpp b/include/beman/optional26/optional.hpp index 1fe04b60..9810bdf4 100644 --- a/include/beman/optional26/optional.hpp +++ b/include/beman/optional26/optional.hpp @@ -283,8 +283,8 @@ class optional { requires(!std::is_reference_v && detail::enable_from_other); template - constexpr explicit(!std::is_convertible_v) optional(const optional& rhs) - requires(detail::enable_from_other); + constexpr explicit(!std::is_convertible_v) optional(const optional& rhs) + requires(std::is_reference_v && detail::enable_from_other); template constexpr explicit(!std::is_convertible_v) optional(optional&& rhs) @@ -328,12 +328,12 @@ class optional { requires(!std::is_reference_v && detail::enable_assign_from_other); template - constexpr optional& operator=(optional&& rhs) - requires(!std::is_reference_v && detail::enable_assign_from_other); + constexpr optional& operator=(const optional& rhs) + requires(std::is_reference_v && detail::enable_assign_from_other); template - constexpr optional& operator=(const optional& rhs) - requires(detail::enable_assign_from_other); + constexpr optional& operator=(optional&& rhs) + requires(!std::is_reference_v && detail::enable_assign_from_other); template constexpr T& emplace(Args&&... args); @@ -477,8 +477,8 @@ inline constexpr optional::optional(const optional& rhs) /// Converting copy constructor for U& template template -inline constexpr optional::optional(const optional& rhs) - requires(detail::enable_from_other) +inline constexpr optional::optional(const optional& rhs) + requires(std::is_reference_v && detail::enable_from_other) { if (rhs.has_value()) { construct(*rhs); @@ -585,8 +585,8 @@ inline constexpr optional& optional::operator=(const optional& rhs) template template -inline constexpr optional& optional::operator=(const optional& rhs) - requires(detail::enable_assign_from_other) +inline constexpr optional& optional::operator=(const optional& rhs) + requires(std::is_reference_v && detail::enable_assign_from_other) { if (has_value()) { if (rhs.has_value()) { @@ -627,7 +627,6 @@ inline constexpr optional& optional::operator=(optional&& rhs) return *this; } - /// Constructs the value in-place, destroying the current one if there is /// one. template From daee5def8f96f6b74f94f9ac8c8067c535ef0aa2 Mon Sep 17 00:00:00 2001 From: Steve Downey Date: Sun, 12 Jan 2025 18:08:02 +0000 Subject: [PATCH 6/9] Rebase on current draft --- include/beman/optional26/optional.hpp | 4 +-- papers/P2988/base-optional.tex | 45 +++++++++++++++++---------- papers/P2988/new-optional.tex | 29 ++++++++--------- 3 files changed, 46 insertions(+), 32 deletions(-) diff --git a/include/beman/optional26/optional.hpp b/include/beman/optional26/optional.hpp index 9810bdf4..4d433d83 100644 --- a/include/beman/optional26/optional.hpp +++ b/include/beman/optional26/optional.hpp @@ -362,9 +362,9 @@ class optional { constexpr T& value() &; constexpr const T& value() const&; constexpr T&& value() &&; - template + template > constexpr T value_or(U&& u) const&; - template + template > constexpr T value_or(U&& u) &&; // \ref{optional.monadic}, monadic operations diff --git a/papers/P2988/base-optional.tex b/papers/P2988/base-optional.tex index 8ab9c6b2..613c2689 100644 --- a/papers/P2988/base-optional.tex +++ b/papers/P2988/base-optional.tex @@ -86,7 +86,7 @@ constexpr void swap(optional&, optional&) noexcept(@\seebelow@); template - constexpr optional<@\seebelow@> make_optional(T&&); + constexpr optional> make_optional(T&&); template constexpr optional make_optional(Args&&... args); template @@ -122,7 +122,7 @@ constexpr explicit optional(in_place_t, Args&&...); template constexpr explicit optional(in_place_t, initializer_list, Args&&...); - template + template> constexpr explicit(@\seebelow@) optional(U&&); template constexpr explicit(@\seebelow@) optional(const optional&); @@ -136,7 +136,7 @@ constexpr optional& operator=(nullopt_t) noexcept; constexpr optional& operator=(const optional&); constexpr optional& operator=(optional&&) noexcept(@\seebelow@); - template constexpr optional& operator=(U&&); + template> constexpr optional& operator=(U&&); template constexpr optional& operator=(const optional&); template constexpr optional& operator=(optional&&); template constexpr T& emplace(Args&&...); @@ -164,8 +164,8 @@ constexpr T& value() &; // freestanding-deleted constexpr T&& value() &&; // freestanding-deleted constexpr const T&& value() const &&; // freestanding-deleted - template constexpr T value_or(U&&) const &; - template constexpr T value_or(U&&) &&; + template> constexpr T value_or(U&&) const &; + template> constexpr T value_or(U&&) &&; // \ref{optional.monadic}, monadic operations template constexpr auto and_then(F&& f) &; @@ -183,7 +183,7 @@ constexpr void reset() noexcept; private: - T *val; // \expos + T* val; // \expos }; template @@ -195,8 +195,7 @@ Any instance of \tcode{optional} at any given time either contains a value or does not contain a value. When an instance of \tcode{optional} \defnx{contains a value}{contains a value!\idxcode{optional}}, it means that an object of type \tcode{T}, referred to as the optional object's \defnx{contained value}{contained value!\idxcode{optional}}, -is allocated within the storage of the optional object. -Implementations are not permitted to use additional storage, such as dynamic memory, to allocate its contained value. +is nested within\iref{intro.object} the optional object. When an object of type \tcode{optional} is contextually converted to \tcode{bool}, the conversion returns \tcode{true} if the object contains a value; otherwise the conversion returns \tcode{false}. @@ -357,7 +356,7 @@ \indexlibraryctor{optional}% \begin{itemdecl} -template constexpr explicit(@\seebelow@) optional(U&& v); +template> constexpr explicit(@\seebelow@) optional(U&& v); \end{itemdecl} \begin{itemdescr} @@ -609,16 +608,18 @@ \indexlibrarymember{operator=}{optional}% \begin{itemdecl} -template constexpr optional& operator=(U&& v); +template> constexpr optional& operator=(U&& v); \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{is_same_v, optional>} is \tcode{false}, -\tcode{conjunction_v, is_same>>} is \tcode{false}, -\tcode{is_constructible_v} is \tcode{true}, and -\tcode{is_assignable_v} is \tcode{true}. +\begin{itemize} +\item \tcode{is_same_v, optional>} is \tcode{false}, +\item \tcode{conjunction_v, is_same>>} is \tcode{false}, +\item \tcode{is_constructible_v} is \tcode{true}, and +\item \tcode{is_assignable_v} is \tcode{true}. +\end{itemize} \pnum \effects @@ -1044,7 +1045,7 @@ \indexlibrarymember{value_or}{optional}% \begin{itemdecl} -template constexpr T value_or(U&& v) const &; +template> constexpr T value_or(U&& v) const &; \end{itemdecl} \begin{itemdescr} @@ -1062,7 +1063,7 @@ \indexlibrarymember{value_or}{optional}% \begin{itemdecl} -template constexpr T value_or(U&& v) &&; +template> constexpr T value_or(U&& v) &&; \end{itemdecl} \begin{itemdescr} @@ -1510,6 +1511,7 @@ \begin{itemdescr} \pnum \constraints +\tcode{U} is not a specialization of \tcode{optional}. The expression \tcode{*x == v} is well-formed and its result is convertible to \tcode{bool}. \begin{note} @@ -1529,6 +1531,7 @@ \begin{itemdescr} \pnum \constraints +\tcode{T} is not a specialization of \tcode{optional}. The expression \tcode{v == *x} is well-formed and its result is convertible to \tcode{bool}. @@ -1545,6 +1548,7 @@ \begin{itemdescr} \pnum \constraints +\tcode{U} is not a specialization of \tcode{optional}. The expression \tcode{*x != v} is well-formed and its result is convertible to \tcode{bool}. @@ -1561,6 +1565,7 @@ \begin{itemdescr} \pnum \constraints +\tcode{T} is not a specialization of \tcode{optional}. The expression \tcode{v != *x} is well-formed and its result is convertible to \tcode{bool}. @@ -1577,6 +1582,7 @@ \begin{itemdescr} \pnum \constraints +\tcode{U} is not a specialization of \tcode{optional}. The expression \tcode{*x < v} is well-formed and its result is convertible to \tcode{bool}. @@ -1593,6 +1599,7 @@ \begin{itemdescr} \pnum \constraints +\tcode{T} is not a specialization of \tcode{optional}. The expression \tcode{v < *x} is well-formed and its result is convertible to \tcode{bool}. @@ -1609,6 +1616,7 @@ \begin{itemdescr} \pnum \constraints +\tcode{U} is not a specialization of \tcode{optional}. The expression \tcode{*x > v} is well-formed and its result is convertible to \tcode{bool}. @@ -1625,6 +1633,7 @@ \begin{itemdescr} \pnum \constraints +\tcode{T} is not a specialization of \tcode{optional}. The expression \tcode{v > *x} is well-formed and its result is convertible to \tcode{bool}. @@ -1641,6 +1650,7 @@ \begin{itemdescr} \pnum \constraints +\tcode{U} is not a specialization of \tcode{optional}. The expression \tcode{*x <= v} is well-formed and its result is convertible to \tcode{bool}. @@ -1657,6 +1667,7 @@ \begin{itemdescr} \pnum \constraints +\tcode{T} is not a specialization of \tcode{optional}. The expression \tcode{v <= *x} is well-formed and its result is convertible to \tcode{bool}. @@ -1673,6 +1684,7 @@ \begin{itemdescr} \pnum \constraints +\tcode{U} is not a specialization of \tcode{optional}. The expression \tcode{*x >= v} is well-formed and its result is convertible to \tcode{bool}. @@ -1689,6 +1701,7 @@ \begin{itemdescr} \pnum \constraints +\tcode{T} is not a specialization of \tcode{optional}. The expression \tcode{v >= *x} is well-formed and its result is convertible to \tcode{bool}. diff --git a/papers/P2988/new-optional.tex b/papers/P2988/new-optional.tex index 3a8d608d..330cb56c 100644 --- a/papers/P2988/new-optional.tex +++ b/papers/P2988/new-optional.tex @@ -92,7 +92,7 @@ constexpr void swap(optional&, optional&) noexcept(@\seebelow@); template - constexpr optional<@\seebelow@> make_optional(T&&); + constexpr optional> make_optional(T&&); template constexpr optional make_optional(Args&&... args); template @@ -129,7 +129,7 @@ constexpr explicit optional(in_place_t, Args&&...); template constexpr explicit optional(in_place_t, initializer_list, Args&&...); - template + template> constexpr explicit(@\seebelow@) optional(U&&); template constexpr explicit(@\seebelow@) optional(const optional&); @@ -151,7 +151,7 @@ constexpr optional& operator=(nullopt_t) noexcept; constexpr optional& operator=(const optional&); constexpr optional& operator=(optional&&) noexcept(@\seebelow@); - template constexpr optional& operator=(U&&); + template> constexpr optional& operator=(U&&); template constexpr optional& operator=(const optional&); \end{codeblock} \color{addclr} @@ -186,8 +186,8 @@ constexpr T& value() &; // freestanding-deleted constexpr T&& value() &&; // freestanding-deleted constexpr const T&& value() const &&; // freestanding-deleted - template constexpr T value_or(U&&) const &; - template constexpr T value_or(U&&) &&; + template> constexpr T value_or(U&&) const &; + template> constexpr T value_or(U&&) &&; // \ref{optional.monadic}, monadic operations template constexpr auto and_then(F&& f) &; @@ -205,7 +205,7 @@ constexpr void reset() noexcept; private: - T *val; // \expos + T* val; // \expos }; template @@ -217,8 +217,7 @@ Any instance of \tcode{optional} at any given time either contains a value or does not contain a value. When an instance of \tcode{optional} \defnx{contains a value}{contains a value!\idxcode{optional}}, it means that an object of type \tcode{T}, referred to as the optional object's \defnx{contained value}{contained value!\idxcode{optional}}, -is allocated within the storage of the optional object. -Implementations are not permitted to use additional storage, such as dynamic memory, to allocate its contained value. +is nested within\iref{intro.object} the optional object. When an object of type \tcode{optional} is contextually converted to \tcode{bool}, the conversion returns \tcode{true} if the object contains a value; otherwise the conversion returns \tcode{false}. @@ -389,7 +388,7 @@ \indexlibraryctor{optional}% \begin{itemdecl} -template constexpr explicit(@\seebelow@) optional(U&& v); +template> constexpr explicit(@\seebelow@) optional(U&& v); \end{itemdecl} \begin{itemdescr} @@ -661,16 +660,18 @@ \indexlibrarymember{operator=}{optional}% \begin{itemdecl} -template constexpr optional& operator=(U&& v); +template> constexpr optional& operator=(U&& v); \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{is_same_v, optional>} is \tcode{false}, -\tcode{conjunction_v, is_same>>} is \tcode{false}, -\tcode{is_constructible_v} is \tcode{true}, and -\tcode{is_assignable_v} is \tcode{true}. +\begin{itemize} +\item \tcode{is_same_v, optional>} is \tcode{false}, +\item \tcode{conjunction_v, is_same>>} is \tcode{false}, +\item \tcode{is_constructible_v} is \tcode{true}, and +\item \tcode{is_assignable_v} is \tcode{true}. +\end{itemize} \pnum \effects From 079b692f231f4e86c1b7c16f7845f6e84347a287 Mon Sep 17 00:00:00 2001 From: Steve Downey Date: Sun, 12 Jan 2025 19:36:05 -0500 Subject: [PATCH 7/9] Clarify problem with copy and assign --- papers/P2988/optional_ref_wording.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/papers/P2988/optional_ref_wording.tex b/papers/P2988/optional_ref_wording.tex index 7a8b95e0..6a502559 100644 --- a/papers/P2988/optional_ref_wording.tex +++ b/papers/P2988/optional_ref_wording.tex @@ -389,7 +389,7 @@ \section{Assignment of optional} This observation allows us to provide only copy-assignment for \tcode{optional}, instead of a set of converting assignments, that would need to replicate the signatures of constructors and their constraints. Assignment from any other value is handled by first implicitly constructing \tcode{optional} and then using copy-assignment. Move-assignment is the same as copy-assignment, since only pointer copy is involved. \section{Copy and Assignment of optional\&\& to optional} -Care must be take to prevent the assignment of a movable optional to disallow the copy or assignment of the underlying referred to value to be stolen. The \tcode{optional const\&} assignment or copy constructor should be used instead. We thank Jan Kokemüller for uncovering this bug. +Care must be take to prevent the assignment of a movable optional to disallow the copy or assignment of the underlying referred to value to be stolen. The \tcode{optional::optional const\&} assignment or copy constructor should be used instead, which also needs to check slightly different constraints for \tcode{converts-from-any-cvref} and for testing \tcode{is_assignable}. We thank Jan Kokemüller for uncovering this bug. The bug seemns to be present in many optional implementations that support references. \chapter{Proposal} From 1babfd9019b2630c0980dc1e19a9e9796a07eb3d Mon Sep 17 00:00:00 2001 From: Steve Downey Date: Sun, 12 Jan 2025 19:36:25 -0500 Subject: [PATCH 8/9] Fix reference problems --- papers/P2988/new-optional.tex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/papers/P2988/new-optional.tex b/papers/P2988/new-optional.tex index 330cb56c..e04f423c 100644 --- a/papers/P2988/new-optional.tex +++ b/papers/P2988/new-optional.tex @@ -564,7 +564,7 @@ \begin{itemdescr} \pnum \effects -See \tref{optional.assign.copy}. +See \tcode{optional.assign.copy}. \begin{lib2dtab2}{\tcode{optional::operator=(const optional\&)} effects}{optional.assign.copy} {\tcode{*this} contains a value} {\tcode{*this} does not contain a value} @@ -615,7 +615,7 @@ \pnum \effects -See \tref{optional.assign.move}. +See \tcode{optional.assign.move}. The result of the expression \tcode{rhs.has_value()} remains unchanged. \begin{lib2dtab2}{\tcode{optional::operator=(optional\&\&)} effects}{optional.assign.move} {\tcode{*this} contains a value} @@ -713,7 +713,7 @@ \pnum \effects -See \tref{optional.assign.copy.templ}. +See \tcode{optional.assign.copy.templ}. \begin{lib2dtab2}{\tcode{optional::operator=(const optional\&)} effects}{optional.assign.copy.templ} {\tcode{*this} contains a value} {\tcode{*this} does not contain a value} @@ -769,7 +769,7 @@ \pnum \effects -See \tref{optional.assign.refcopy.templ}. +See \tcode{optional.assign.refcopy.templ}. \begin{lib2dtab2}{\tcode{optional::operator=(const optional\&)} effects}{optional.assign.refcopy.templ} {\tcode{*this} contains a value} {\tcode{*this} does not contain a value} @@ -828,7 +828,7 @@ \pnum \effects -See \tref{optional.assign.move.templ}. +See \tcode{optional.assign.move.templ}. The result of the expression \tcode{rhs.has_value()} remains unchanged. \begin{lib2dtab2}{\tcode{optional::operator=(optional\&\&)} effects}{optional.assign.move.templ} {\tcode{*this} contains a value} From d4811006b43bb0c7e91cd8e678eda7a22bdc031e Mon Sep 17 00:00:00 2001 From: Steve Downey Date: Sat, 18 Jan 2025 17:16:23 -0500 Subject: [PATCH 9/9] Lint fix -- newline and EOF --- papers/P2988/mybiblio.bib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/papers/P2988/mybiblio.bib b/papers/P2988/mybiblio.bib index 7c14e99a..bbe93d90 100644 --- a/papers/P2988/mybiblio.bib +++ b/papers/P2988/mybiblio.bib @@ -66,4 +66,4 @@ @misc{The_Beman_Project_beman_optional26 howpublished = {\url{https://github.com/bemanproject/optional26}}, month = {}, year = {}, -} \ No newline at end of file +}