This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Open status.
4015. LWG 3973 brokeconst
overloads of std::optional
monadic operations
Section: 22.5.3.8 [optional.monadic] Status: Open Submitter: Jonathan Wakely Opened: 2023-11-24 Last modified: 2024-10-02
Priority: 1
View all issues with Open status.
Discussion:
The resolution of LWG 3973(i) (adopted in Kona) changed all occurrences of value()
to *val
. The intention was not to change the meaning, just avoid the non-freestanding value()
function, and avoid ADL that would be caused by using **this
. However, in the const
overloads such as and_then(F&&) const
the type of value()
was const T&
, but the type of *val
is always T&
. This implies that the const overloads invoke the callable with a non-const argument, which is incorrect (and would be undefined behaviour for a const std::optional<T>
).
On the LWG reflector it was suggested that we should rewrite the specification of std::optional
to stop using an exposition-only data member of type T*
. No such member ever exists in real implemetations, so it is misleading and leads to specification bugs of this sort.
Change the class definition in 22.5.3.1 [optional.optional.general] to use a union, and update every use of val
accordingly throughout 22.5.3 [optional.optional]. For consistency with 22.8.6.1 [expected.object.general] we might also want to introduce a bool has_val
member and refer to that in the specification.
private: T *val; // exposition only bool has_val; // exposition only union { T val; // exposition only }; };
For example, in 22.5.3.9 [optional.mod]:
-1- Effects: If
*this
contains a value, callsval -> .T::~T()
to destroy the contained value and setshas_val
tofalse
; otherwise no effect.
[2023-11-26; Daniel provides wording]
The proposed wording is considerably influenced by that of the specification of expected
, but attempts to reduce the amount of changes to not perfectly mimic it. Although "the contained value" is a magic word of power it seemed feasible and simpler to use the new exposition-only member val
directly in some (but not all) places, usually involved with initializations.
has_val
to true/false
" where either the Effects wording says "otherwise no effect" or in other cases if the postconditions did not already say that indirectly. I also added extra mentioning of has_val
changes in tables where different cells had very different effects on that member (unless these cells specify postconditions), to prevent misunderstanding.
[2024-03-11; Reflector poll]
Set priority to 1 after reflector poll in November 2023. Six votes for 'Tentatively Ready' but enough uncertainty to deserve discussion at a meeting.
Previous resolution [SUPERSEDED]:
This wording is relative to N4964 after application of the wording of LWG 3973(i).
Modify 22.5.3.1 [optional.optional.general], class template
optional
synopsis, as indicated:namespace std { template<class T> class optional { public: using value_type = T; […] private: bool has_val; // exposition only union { T val*val; // exposition only }; }; […] }Modify 22.5.3.1 [optional.optional.general] as indicated:
-2- Member
has_val
indicates whether anoptional<T>
object contains a value When anoptional<T>
object contains a value, memberval
points to the contained value.Modify 22.5.3.2 [optional.ctor] as indicated:
[Drafting note: Normatively, this subclause doesn't require any changes, but I'm suggesting to replace phrases of the form "[…]initializes the contained value with"] by "[…]initializes
val
with" as we do in 22.8.6.2 [expected.object.cons]. I intentionally did not add extra "and setshas_val
totrue/false
" since those effects are already guaranteed by the postconditions]constexpr optional(const optional& rhs);-4- Effects: If
-5- Postconditions:rhs
contains a value, direct-non-list-initializesval
the contained value with*rhs .val
.rhs.has_value() == this->has_value()
. […]constexpr optional(optional&& rhs) noexcept(see below);-8- Constraints: […]
-9- Effects: Ifrhs
contains a value, direct-non-list-initializesval
the contained value withstd::move( *rhs .val)
.rhs.has_value()
is unchanged. -10- Postconditions:rhs.has_value() == this->has_value()
. […]template<class... Args> constexpr explicit optional(in_place_t, Args&&... args);-13- Constraints: […]
-14- Effects: Direct-non-list-initializesval
the contained value withstd::forward<Args>(args)...
. -15- Postconditions:*this
contains a value. […]template<class U, class... Args> constexpr explicit optional(in_place_t, initializer_list<U> il, Args&&... args);-18- Constraints: […]
-19- Effects: Direct-non-list-initializesval
the contained value withil, std::forward<Args>(args)...
. -20- Postconditions:*this
contains a value. […]template<class U = T> constexpr explicit(see below) optional(U&& v);-23- Constraints: […]
-24- Effects: Direct-non-list-initializesval
the contained value withstd::forward<U>(v)
. -25- Postconditions:*this
contains a value. […]template<class U> constexpr explicit(see below) optional(const optional<U>& rhs);-28- Constraints: […]
-29- Effects: Ifrhs
contains a value, direct-non-list-initializesval
the contained value with*rhs .val
. -30- Postconditions:rhs.has_value() == this->has_value()
. […]template<class U> constexpr explicit(see below) optional(optional<U>&& rhs);-33- Constraints: […]
-34- Effects: Ifrhs
contains a value, direct-non-list-initializesval
the contained value withstd::move( *rhs .val)
.rhs.has_value()
is unchanged. -35- Postconditions:rhs.has_value() == this->has_value()
. […]Modify 22.5.3.3 [optional.dtor] as indicated:
constexpr ~optional();-1- Effects: If
is_trivially_destructible_v<T> != true
and*this
contains a value, callsval-> val.T::~T()
.Modify 22.5.3.4 [optional.assign] as indicated:
constexpr optional<T>& operator=(nullopt_t) noexcept;-1- Effects: If
-2- Postconditions:*this
contains a value, callsval-> val.T::~T()
to destroy the contained value and setshas_val
tofalse
; otherwise no effect.*this
does not contain a value.constexpr optional<T>& operator=(const optional& rhs);-4- Effects: See Table 58.
Table 58 —optional::operator=(const optional&)
effects [tab:optional.assign.copy]*this
contains a value*this
does not contain a valuerhs
contains a value assigns*rhs .val
toval
the contained value direct-non-list-initializesval
the contained value with*rhs .val
and setshas_val
totrue
rhs
does not contain a value destroys the contained value by callingval-> val.T::~T()
and setshas_val
tofalse
no effect-5- Postconditions:
[…]rhs.has_value() == this->has_value()
.constexpr optional<T>& operator=(optional&& rhs) noexcept(see below);-8- Constraints: […]
-9- Effects: See Table 59. The result of the expressionrhs.has_value()
remains unchanged. -10- Postconditions:rhs.has_value() == this->has_value()
. -11- Returns:*this
. Table 59 —optional::operator=(optional&&)
effects [tab:optional.assign.move]*this
contains a value*this
does not contain a valuerhs
contains a value assignsstd::move( *rhs .val)
toval
the contained value direct-non-list-initializesval
the contained value withstd::move( *rhs .val)
and setshas_val
totrue
rhs
does not contain a value destroys the contained value by callingval-> val.T::~T()
and setshas_val
tofalse
no effect-12- Remarks: […]
-13- If any exception is thrown, the result of the expressionthis->has_value()
remains unchanged. If an exception is thrown during the call toT
's move constructor, the state of*rhs. val val
is determined by the exception safety guarantee ofT
's move constructor. If an exception is thrown during the call toT
's move assignment, the state of* val val
and*rhs. val val
is determined by the exception safety guarantee ofT
's move assignment.template<class U = T> constexpr optional<T>& operator=(U&& v);-14- Constraints: […]
-15- Effects: If*this
contains a value, assignsstd::forward<U>(v)
toval
the contained value; otherwise direct-non-list-initializesval
the contained value withstd::forward<U>(v)
. -16- Postconditions:*this
contains a value. -17- Returns:*this
. -18- Remarks: If any exception is thrown, the result of the expressionthis->has_value()
remains unchanged. If an exception is thrown during the call toT
's constructor, the state ofv
is determined by the exception safety guarantee ofT
's constructor. If an exception is thrown during the call toT
's assignment, the state ofval *val
andv
is determined by the exception safety guarantee ofT
's assignment.template<class U> constexpr optional<T>& operator=(const optional<U>& rhs);-19- Constraints: […]
-20- Effects: See Table 60. Table 60 —optional::operator=(const optional<U>&)
effects [tab:optional.assign.copy.templ]*this
contains a value*this
does not contain a valuerhs
contains a value assigns*rhs .val
toval
the contained value direct-non-list-initializesval
the contained value with*rhs .val
and setshas_val
totrue
rhs
does not contain a value destroys the contained value by callingval-> val.T::~T()
and setshas_val
tofalse
no effect-21- Postconditions:
-22- Returns:rhs.has_value() == this->has_value()
.*this
. -23- If any exception is thrown, the result of the expressionthis->has_value()
remains unchanged. If an exception is thrown during the call toT
's constructor, the state of*rhs. val val
is determined by the exception safety guarantee ofT
's constructor. If an exception is thrown during the call toT
's assignment, the state ofval *val
and*rhs. val val
is determined by the exception safety guarantee ofT
's assignment.template<class U> constexpr optional<T>& operator=(optional<U>&& rhs);-24- Constraints: […]
-25- Effects: See Table 61. The result of the expressionrhs.has_value()
remains unchanged. Table 61 —optional::operator=(optional<U>&&)
effects [tab:optional.assign.move.templ]*this
contains a value*this
does not contain a valuerhs
contains a value assignsstd::move( *rhs .val)
toval
the contained value direct-non-list-initializesval
the contained value withstd::move( *rhs .val)
and setshas_val
totrue
rhs
does not contain a value destroys the contained value by callingval-> val.T::~T()
and setshas_val
tofalse
no effect-26- Postconditions:
-27- Returns:rhs.has_value() == this->has_value()
.*this
. -28- If any exception is thrown, the result of the expressionthis->has_value()
remains unchanged. If an exception is thrown during the call toT
's constructor, the state of*rhs. val val
is determined by the exception safety guarantee ofT
's constructor. If an exception is thrown during the call toT
's assignment, the state ofval *val
and*rhs. val val
is determined by the exception safety guarantee ofT
's assignment.template<class... Args> constexpr T& emplace(Args&&... args);-29- Mandates: […]
-30- Effects: Calls*this = nullopt
. Then direct-non-list-initializesval
the contained value withstd::forward<Args>(args)...
. -31- Postconditions:*this
contains a value. -32- Returns:val
A reference to the new contained value. […] -34- Remarks: If an exception is thrown during the call toT
's constructor,*this
does not contain a value, and the previousval *val
(if any) has been destroyed.template<class U, class... Args> constexpr T& emplace(initializer_list<U> il, Args&&... args);-35- Constraints: […]
-36- Effects: Calls*this = nullopt
. Then direct-non-list-initializesval
the contained value withil, std::forward<Args>(args)...
. -37- Postconditions:*this
contains a value. -38- Returns:val
A reference to the new contained value. […] -40- Remarks: If an exception is thrown during the call toT
's constructor,*this
does not contain a value, and the previousval *val
(if any) has been destroyed.Modify 22.5.3.5 [optional.swap] as indicated:
constexpr void swap(optional& rhs) noexcept(see below);-1- Mandates: […]
-2- Preconditions: […] -3- Effects: See Table 62. Table 62 —optional::swap(optional&)
effects [tab:optional.swap]*this
contains a value*this
does not contain a valuerhs
contains a value callsswap( val *(*this), *rhs .val)
direct-non-list-initializesval
the contained value of*this
withstd::move( *rhs .val)
, followed byrhs. val. val->T::~T()
;
postcondition is that*this
contains a value andrhs
does
not contain a valuerhs
does not contain a value direct-non-list-initializes the contained value ofrhs .val
withstd::move( val *(*this))
, followed byval. val->T::~T()
;
postcondition is that*this
does not contain a value andrhs
contains a value no effect-4- Throws: […]
-5- Remarks: […] -6- If any exception is thrown, the results of the expressionsthis->has_value()
andrhs.has_value()
remain unchanged. If an exception is thrown during the call to functionswap
, the state ofval *val
and*rhs. val val
is determined by the exception safety guarantee ofswap
for lvalues ofT
. If an exception is thrown during the call toT
's move constructor, the state ofval *val
and*rhs. val val
is determined by the exception safety guarantee ofT
's move constructor.Modify 22.5.3.7 [optional.observe] as indicated:
constexpr const T* operator->() const noexcept; constexpr T* operator->() noexcept;-1- Preconditions:
-2- Returns:*this
contains a value.addressof(val) val
. -3- […]constexpr const T& operator*() const & noexcept; constexpr T& operator*() & noexcept;-4- Preconditions:
-5- Returns:*this
contains a value.val *val
. -6- […]constexpr T&& operator*() && noexcept; constexpr const T&& operator*() const && noexcept;-7- Preconditions:
-8- Effects: Equivalent to:*this
contains a value.return std::move( val *val);
constexpr explicit operator bool() const noexcept;-9- Returns:
-10- Remarks: This function is a constexpr function.true
if and only if*this
contains a value.constexpr bool has_value() const noexcept;-11- Returns:
-12- Remarks: These functions are This function is a constexpr function s.has_val
true
if and only if*this
contains a value.constexpr const T& value() const &; constexpr T& value() &;-13- Effects: Equivalent to:
return has_value() ? val*val : throw bad_optional_access();constexpr T&& value() &&; constexpr const T&& value() const &&;-14- Effects: Equivalent to:
return has_value() ? std::move(val*val) : throw bad_optional_access();template<class U> constexpr T value_or(U&& v) const &;-15- Mandates: […]
-16- Effects: Equivalent to:return has_value() ? val**this : static_cast<T>(std::forward<U>(v));template<class U> constexpr T value_or(U&& v) &&;-17- Mandates: […]
-18- Effects: Equivalent to:return has_value() ? std::move(val**this) : static_cast<T>(std::forward<U>(v));Modify 22.5.3.8 [optional.monadic] as indicated:
template<class F> constexpr auto and_then(F&& f) &; template<class F> constexpr auto and_then(F&& f) const &;-1- Let
-2- Mandates: […] -3- Effects: Equivalent to:U
beinvoke_result_t<F, decltype( (val) *val)>
.if (*this) { return invoke(std::forward<F>(f), val*val); } else { return remove_cvref_t<U>(); }template<class F> constexpr auto and_then(F&& f) &&; template<class F> constexpr auto and_then(F&& f) const &&;-4- Let
-5- Mandates: […] -6- Effects: Equivalent to:U
beinvoke_result_t<F, decltype(std::move( val *val))>
.if (*this) { return invoke(std::forward<F>(f), std::move(val*val)); } else { return remove_cvref_t<U>(); }template<class F> constexpr auto transform(F&& f) &; template<class F> constexpr auto transform(F&& f) const &;-7- Let
-8- Mandates:U
beremove_cv_t<invoke_result_t<F, decltype( (val) *val)>>
.U
is a non-array object type other thanin_place_t
ornullopt_t
. The declarationU u(invoke(std::forward<F>(f), val*val));is well-formed for some invented variable
[…] -9- Returns: Ifu
.*this
contains a value, anoptional<U>
object whose contained value is direct-non-list-initialized withinvoke(std::forward<F>(f), val *val)
; otherwise,optional<U>()
.template<class F> constexpr auto transform(F&& f) &&; template<class F> constexpr auto transform(F&& f) const &&;-10- Let
-11- Mandates:U
beremove_cv_t<invoke_result_t<F, decltype(std::move( val *val))>>
.U
is a non-array object type other thanin_place_t
ornullopt_t
. The declarationU u(invoke(std::forward<F>(f), std::move(val*val)));is well-formed for some invented variable
[…] -12- Returns: Ifu
.*this
contains a value, anoptional<U>
object whose contained value is direct-non-list-initialized withinvoke(std::forward<F>(f), std::move( val *val))
; otherwise,optional<U>()
.Modify 22.5.3.9 [optional.mod] as indicated:
constexpr void reset() noexcept;-1- Effects: If
-2- Postconditions:*this
contains a value, callsval-> val.T::~T()
to destroy the contained value and setshas_val
tofalse
; otherwise no effect.*this
does not contain a value.
[St. Louis 2024-06-24; Jonathan provides improved wording]
[2024-08-21; LWG telecon]
During telecon review it was suggested to replace 22.5.3.1 [optional.optional.general] p1 and p2. On the reflector Daniel requested to keep the "additional storage" prohibition, so that will be addressed by issue 4141(i) instead.
[2024-10-02; Jonathan tweaks proposed resolution]
On the reflector we decided that the union member should use remove_cv_t
, as proposed for expected
by issue 3891(i). The rest of the proposed resolution is unchanged, so that edit was made in-place below, instead of as a new resolution that supersedes the old one.
Proposed resolution:
This wording is relative to N4988.
Modify 22.5.3.1 [optional.optional.general], class template optional
synopsis, as indicated:
namespace std { template<class T> class optional { public: using value_type = T; […] private: *val // exposition only; union { remove_cv_t<T> val; // exposition only }; }; […] }
Modify 22.5.3.1 [optional.optional.general] as indicated:
-1- When its member
val
is active (11.5.1 [class.union.general]), an instance ofoptional<T>
is said to contain a value, andval
is referred to as its contained value. Any instance ofoptional<T>
at any given time either contains a value or does not contain a value. When an instance ofoptional<T>
contains a value, it means that an object of typeT
, referred to as the An optional object's contained value contained value, 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. When an object of typeoptional<T>
is contextually converted tobool
, the conversion returnstrue
if the object contains a value; otherwise the conversion returnsfalse
.-2- When an
optional<T>
object contains a value, memberval
points to the contained value.
Modify 22.5.3.2 [optional.ctor] as indicated:
constexpr optional(const optional& rhs);-4- Effects: If
-5- Postconditions:rhs
contains a value, direct-non-list-initializesval
the contained value with*rhs .val
.rhs.has_value() == this->has_value()
. […]constexpr optional(optional&& rhs) noexcept(see below);-8- Constraints: […]
-9- Effects: Ifrhs
contains a value, direct-non-list-initializesval
the contained value withstd::move( *rhs .val)
.rhs.has_value()
is unchanged. -10- Postconditions:rhs.has_value() == this->has_value()
. […]template<class... Args> constexpr explicit optional(in_place_t, Args&&... args);-13- Constraints: […]
-14- Effects: Direct-non-list-initializesval
the contained value withstd::forward<Args>(args)...
. -15- Postconditions:*this
contains a value. […]template<class U, class... Args> constexpr explicit optional(in_place_t, initializer_list<U> il, Args&&... args);-18- Constraints: […]
-19- Effects: Direct-non-list-initializesval
the contained value withil, std::forward<Args>(args)...
. -20- Postconditions:*this
contains a value. […]template<class U = T> constexpr explicit(see below) optional(U&& v);-23- Constraints: […]
-24- Effects: Direct-non-list-initializesval
the contained value withstd::forward<U>(v)
. -25- Postconditions:*this
contains a value. […]template<class U> constexpr explicit(see below) optional(const optional<U>& rhs);-28- Constraints: […]
-29- Effects: Ifrhs
contains a value, direct-non-list-initializesval
the contained value with*rhs .val
. -30- Postconditions:rhs.has_value() == this->has_value()
. […]template<class U> constexpr explicit(see below) optional(optional<U>&& rhs);-33- Constraints: […]
-34- Effects: Ifrhs
contains a value, direct-non-list-initializesval
the contained value withstd::move( *rhs .val)
.rhs.has_value()
is unchanged. -35- Postconditions:rhs.has_value() == this->has_value()
. […]
Modify 22.5.3.3 [optional.dtor] as indicated:
constexpr ~optional();-1- Effects: If
is_trivially_destructible_v<T> != true
and*this
contains a value, callsval-> val.T::~T()
.
Modify 22.5.3.4 [optional.assign] as indicated:
constexpr optional<T>& operator=(nullopt_t) noexcept;-1- Effects: If
-2- Postconditions:*this
contains a value, callsval-> val.T::~T()
to destroy the contained value; otherwise no effect.*this
does not contain a value.constexpr optional<T>& operator=(const optional& rhs);-4- Effects: See Table 58.
Table 58 —optional::operator=(const optional&)
effects [tab:optional.assign.copy]*this
contains a value*this
does not contain a valuerhs
contains a value assigns*rhs .val
toval
the contained value direct-non-list-initializesval
the contained value with*rhs .val
rhs
does not contain a value destroys the contained value by callingval-> val.T::~T()
no effect-5- Postconditions:
[…]rhs.has_value() == this->has_value()
.constexpr optional<T>& operator=(optional&& rhs) noexcept(see below);-8- Constraints: […]
-9- Effects: See Table 59. The result of the expressionrhs.has_value()
remains unchanged. -10- Postconditions:rhs.has_value() == this->has_value()
. -11- Returns:*this
. Table 59 —optional::operator=(optional&&)
effects [tab:optional.assign.move]*this
contains a value*this
does not contain a valuerhs
contains a value assignsstd::move( *rhs .val)
toval
the contained value direct-non-list-initializesval
the contained value withstd::move( *rhs .val)
rhs
does not contain a value destroys the contained value by callingval-> val.T::~T()
no effect-12- Remarks: […]
-13- If any exception is thrown, the result of the expressionthis->has_value()
remains unchanged. If an exception is thrown during the call toT
's move constructor, the state of*rhs. val val
is determined by the exception safety guarantee ofT
's move constructor. If an exception is thrown during the call toT
's move assignment, the states state of* val val
and*rhs. val val
are is determined by the exception safety guarantee ofT
's move assignment.template<class U = T> constexpr optional<T>& operator=(U&& v);-14- Constraints: […]
-15- Effects: If*this
contains a value, assignsstd::forward<U>(v)
toval
the contained value; otherwise direct-non-list-initializesval
the contained value withstd::forward<U>(v)
. -16- Postconditions:*this
contains a value. -17- Returns:*this
. -18- Remarks: If any exception is thrown, the result of the expressionthis->has_value()
remains unchanged. If an exception is thrown during the call toT
's constructor, the state ofv
is determined by the exception safety guarantee ofT
's constructor. If an exception is thrown during the call toT
's assignment, the states state ofval *val
andv
are is determined by the exception safety guarantee ofT
's assignment.template<class U> constexpr optional<T>& operator=(const optional<U>& rhs);-19- Constraints: […]
-20- Effects: See Table 60. Table 60 —optional::operator=(const optional<U>&)
effects [tab:optional.assign.copy.templ]*this
contains a value*this
does not contain a valuerhs
contains a value assigns*rhs .val
toval
the contained value direct-non-list-initializesval
the contained value with*rhs .val
rhs
does not contain a value destroys the contained value by callingval-> val.T::~T()
no effect-21- Postconditions:
-22- Returns:rhs.has_value() == this->has_value()
.*this
. -23- If any exception is thrown, the result of the expressionthis->has_value()
remains unchanged. If an exception is thrown during the call toT
's constructor, the state of*rhs. val val
is determined by the exception safety guarantee ofT
's constructor. If an exception is thrown during the call toT
's assignment, the states state ofval *val
and*rhs. val val
are is determined by the exception safety guarantee ofT
's assignment.template<class U> constexpr optional<T>& operator=(optional<U>&& rhs);-24- Constraints: […]
-25- Effects: See Table 61. The result of the expressionrhs.has_value()
remains unchanged. Table 61 —optional::operator=(optional<U>&&)
effects [tab:optional.assign.move.templ]*this
contains a value*this
does not contain a valuerhs
contains a value assignsstd::move( *rhs .val)
toval
the contained value direct-non-list-initializesval
the contained value withstd::move( *rhs .val)
rhs
does not contain a value destroys the contained value by callingval-> val.T::~T()
no effect-26- Postconditions:
-27- Returns:rhs.has_value() == this->has_value()
.*this
. -28- If any exception is thrown, the result of the expressionthis->has_value()
remains unchanged. If an exception is thrown during the call toT
's constructor, the state of*rhs. val val
is determined by the exception safety guarantee ofT
's constructor. If an exception is thrown during the call toT
's assignment, the states state ofval *val
and*rhs. val val
are is determined by the exception safety guarantee ofT
's assignment.template<class... Args> constexpr T& emplace(Args&&... args);-29- Mandates: […]
-30- Effects: Calls*this = nullopt
. Then direct-non-list-initializesval
the contained value withstd::forward<Args>(args)...
. -31- Postconditions:*this
contains a value. -32- Returns:val
A reference to the new contained value. […] -34- Remarks: If an exception is thrown during the call toT
's constructor,*this
does not contain a value, and the previousval *val
(if any) has been destroyed.template<class U, class... Args> constexpr T& emplace(initializer_list<U> il, Args&&... args);-35- Constraints: […]
-36- Effects: Calls*this = nullopt
. Then direct-non-list-initializesval
the contained value withil, std::forward<Args>(args)...
. -37- Postconditions:*this
contains a value. -38- Returns:val
A reference to the new contained value. […] -40- Remarks: If an exception is thrown during the call toT
's constructor,*this
does not contain a value, and the previousval *val
(if any) has been destroyed.
Modify 22.5.3.5 [optional.swap] as indicated:
constexpr void swap(optional& rhs) noexcept(see below);-1- Mandates: […]
-2- Preconditions: […] -3- Effects: See Table 62. Table 62 —optional::swap(optional&)
effects [tab:optional.swap]*this
contains a value*this
does not contain a valuerhs
contains a value callsswap( val *(*this), *rhs .val)
direct-non-list-initializesval
the contained value of*this
withstd::move( *rhs .val)
, followed byrhs. val. val->T::~T()
;
postcondition is that*this
contains a value andrhs
does
not contain a valuerhs
does not contain a value direct-non-list-initializes the contained value ofrhs .val
withstd::move( val *(*this))
, followed byval. val->T::~T()
;
postcondition is that*this
does not contain a value andrhs
contains a value no effect-4- Throws: […]
-5- Remarks: […] -6- If any exception is thrown, the results of the expressionsthis->has_value()
andrhs.has_value()
remain unchanged. If an exception is thrown during the call to functionswap
, the state ofval *val
and*rhs. val val
is determined by the exception safety guarantee ofswap
for lvalues ofT
. If an exception is thrown during the call toT
's move constructor, the states state ofval *val
and*rhs. val val
are is determined by the exception safety guarantee ofT
's move constructor.
Modify 22.5.3.7 [optional.observe] as indicated:
constexpr const T* operator->() const noexcept; constexpr T* operator->() noexcept;-1- Preconditions:
-2- Returns:*this
contains a value.addressof(val) val
. -3- […]constexpr const T& operator*() const & noexcept; constexpr T& operator*() & noexcept;-4- Preconditions:
-5- Returns:*this
contains a value.val *val
. -6- […]constexpr T&& operator*() && noexcept; constexpr const T&& operator*() const && noexcept;-7- Preconditions:
-8- Effects: Equivalent to:*this
contains a value.return std::move( val *val);
constexpr explicit operator bool() const noexcept;-9- Returns:
-10- Remarks: This function is a constexpr function.true
if and only if*this
contains a value.constexpr bool has_value() const noexcept;-11- Returns:
-12- Remarks: This function is a constexpr function.true
if and only if*this
contains a value.constexpr const T& value() const &; constexpr T& value() &;-13- Effects: Equivalent to:
return has_value() ? val*val : throw bad_optional_access();constexpr T&& value() &&; constexpr const T&& value() const &&;-14- Effects: Equivalent to:
return has_value() ? std::move(val*val) : throw bad_optional_access();template<class U> constexpr T value_or(U&& v) const &;-15- Mandates: […]
-16- Effects: Equivalent to:return has_value() ? val**this : static_cast<T>(std::forward<U>(v));template<class U> constexpr T value_or(U&& v) &&;-17- Mandates: […]
-18- Effects: Equivalent to:return has_value() ? std::move(val**this) : static_cast<T>(std::forward<U>(v));
Modify 22.5.3.8 [optional.monadic] as indicated:
template<class F> constexpr auto and_then(F&& f) &; template<class F> constexpr auto and_then(F&& f) const &;-1- Let
-2- Mandates: […] -3- Effects: Equivalent to:U
beinvoke_result_t<F, decltype( (val) *val)>
.if (*this) { return invoke(std::forward<F>(f), val*val); } else { return remove_cvref_t<U>(); }template<class F> constexpr auto and_then(F&& f) &&; template<class F> constexpr auto and_then(F&& f) const &&;-4- Let
-5- Mandates: […] -6- Effects: Equivalent to:U
beinvoke_result_t<F, decltype(std::move( val *val))>
.if (*this) { return invoke(std::forward<F>(f), std::move(val*val)); } else { return remove_cvref_t<U>(); }template<class F> constexpr auto transform(F&& f) &; template<class F> constexpr auto transform(F&& f) const &;-7- Let
-8- Mandates:U
beremove_cv_t<invoke_result_t<F, decltype( (val) *val)>>
.U
is a non-array object type other thanin_place_t
ornullopt_t
. The declarationU u(invoke(std::forward<F>(f), val*val));is well-formed for some invented variable
[…] -9- Returns: Ifu
.*this
contains a value, anoptional<U>
object whose contained value is direct-non-list-initialized withinvoke(std::forward<F>(f), val *val)
; otherwise,optional<U>()
.template<class F> constexpr auto transform(F&& f) &&; template<class F> constexpr auto transform(F&& f) const &&;-10- Let
-11- Mandates:U
beremove_cv_t<invoke_result_t<F, decltype(std::move( val *val))>>
.U
is a non-array object type other thanin_place_t
ornullopt_t
. The declarationU u(invoke(std::forward<F>(f), std::move(val*val)));is well-formed for some invented variable
[…] -12- Returns: Ifu
.*this
contains a value, anoptional<U>
object whose contained value is direct-non-list-initialized withinvoke(std::forward<F>(f), std::move( val *val))
; otherwise,optional<U>()
.
Modify 22.5.3.9 [optional.mod] as indicated:
constexpr void reset() noexcept;-1- Effects: If
-2- Postconditions:*this
contains a value, callsval-> val.T::~T()
to destroy the contained value; otherwise no effect.*this
does not contain a value.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4