optional::value_or
should never return a cv-qualified typeSection: 22.5.3.7 [optional.observe] Status: New Submitter: Casey Carter Opened: 2020-04-02 Last modified: 2023-02-10
Priority: 3
View other active issues in [optional.observe].
View all other issues in [optional.observe].
View all issues with New status.
Discussion:
The optional<T>::value_or
overloads are specified to return T
. This seems silly when
T
is const
or volatile
qualified — return types should never be cv-qualified.
(In the volatile
case, it is even deprecated since merging P1152R4
"Deprecating volatile" into the working draft.) We should strip cv-qualifiers from these return types.
[2020-04-18 Issue Prioritization]
Priority to 3 after reflector discussion.
Previous resolution [SUPERSEDED]:
This wording is relative to N4861.
Modify 22.5.3 [optional.optional] as indicated:
[…] template<class U> constexpr remove_cv_t<T> value_or(U&&) const&; template<class U> constexpr remove_cv_t<T> value_or(U&&) &&; […]Modify 22.5.3.7 [optional.observe] as indicated:
template<class U> constexpr remove_cv_t<T> value_or(U&& v) const&;-?- Let
-17- Mandates:R
beremove_cv_t<T>
.is
is_copy_constructible_v<T>is_convertible_v<const T&, R> && is_convertible_v<U&&, T>true
. -18- Effects: Equivalent to:return bool(*this) ? **this : static_cast<TR>(std::forward<U>(v));template<class U> constexpr remove_cv_t<T> value_or(U&& v) &&;-?- Let
-19- Mandates:R
beremove_cv_t<T>
.is
is_move_constructible_v<T>is_convertible_v<T, R> && is_convertible_v<U&&, T>true
. -20- Effects: Equivalent to:return bool(*this) ? std::move(**this) : static_cast<TR>(std::forward<U>(v));
[2023-02-09 Casey improves wording and expands to cover expected::value_or
]
Since expected
was modeled on optional
, it has the same issue.
Proposed resolution:
This wording is relative to N4928.
Modify 22.5.3.1 [optional.optional.general] as indicated:
[…] template<class U> constexpr remove_cv_t<T> value_or(U&&) const&; template<class U> constexpr remove_cv_t<T> value_or(U&&) &&; […]
Modify 22.5.3.7 [optional.observe] as indicated:
[Drafting note: The two removals of the
&&
inis_convertible_v<U&&, T>
below is a simplification to restore consistency with the wording forexpected::value_or
.]
template<class U> constexpr remove_cv_t<T> value_or(U&& v) const &;-?- Let
-15- Mandates:R
beremove_cv_t<T>
.is
is_copy_constructible_v<T>is_convertible_v<const T&, R> && is_convertible_v<U&&,TR>true
. -16- Effects: Equivalent to:return bool(*this) ? **this : static_cast<TR>(std::forward<U>(v));template<class U> constexpr remove_cv_t<T> value_or(U&& v) &&;-?- Let
-17- Mandates:R
beremove_cv_t<T>
.is
is_move_constructible_v<T>is_convertible_v<T, R> && is_convertible_v<U&&,TR>true
. -18- Effects: Equivalent to:return bool(*this) ? std::move(**this) : static_cast<TR>(std::forward<U>(v));
Modify 22.8.6.1 [expected.object.general] as indicated:
[…] template<class U> constexpr remove_cv_t<T> value_or(U&&) const &; template<class U> constexpr remove_cv_t<T> value_or(U&&) &&; […]
Modify 22.8.6.6 [expected.object.obs] as indicated:
template<class U> constexpr remove_cv_t<T> value_or(U&& v) const &;-?- Let
-16- Mandates:R
beremove_cv_t<T>
.is
is_copy_constructible_v<T>is_convertible_v<const T&, R> && is_convertible_v<U,TR>true
. -17- Returns:has_value() ? **this : static_cast<
.TR>(std::forward<U>(v))template<class U> constexpr remove_cv_t<T> value_or(U&& v) &&;-?- Let
-18- Mandates:R
beremove_cv_t<T>
.is
is_move_constructible_v<T>is_convertible_v<T, R> && is_convertible_v<U,TR>true
. -19- Returns:has_value() ? std::move(**this) : static_cast<
.TR>(std::forward<U>(v))