Section: 22.5.3.1 [optional.optional.general], 22.8.6.1 [expected.object.general] Status: Tentatively Ready Submitter: Casey Carter Opened: 2023-02-13 Last modified: 2024-09-19
Priority: 3
View other active issues in [optional.optional.general].
View all other issues in [optional.optional.general].
View all issues with Tentatively Ready status.
Discussion:
While implementing P2505R5 "Monadic Functions for std::expected
" we found it odd that
the template type parameter for the assignment operator that accepts an argument by forwarding reference is
defaulted, but the template type parameter for value_or
is not. For consistency, it would seem that
meow.value_or(woof)
should accept the same arguments woof
as does
meow = woof
, even when those arguments are braced-initializers.
value_or
to T
instead of remove_cv_t<T>
. For expected<const vector<int>, int> meow{unexpect, 42};
,
for example, meow.value_or({1, 2, 3})
would create a temporary const vector<int>
for the argument and return a copy of that argument. Were the default template argument instead
remove_cv_t<T>
, meow.value_or({1, 2, 3})
could move construct its return value
from the argument vector<int>
. For the same reason, the constructor that accepts a forwarding
reference with a default template argument of T
should default that argument to remove_cv_t<T>
.
For consistency, it would be best to default the template argument of the perfect-forwarding construct,
perfect-forwarding assignment operator, and value_or
to remove_cv_t<T>
. Since all of
the arguments presented apply equally to optional
, we believe optional
should be changed
consistently with expected
. MSVCSTL has prototyped these changes successfully.
[2023-03-22; Reflector poll]
Set priority to 3 after reflector poll.
[2024-09-18; Reflector poll]
Set status to Tentatively Ready after six votes in favour during reflector poll.
Proposed resolution:
This wording is relative to N4928.
Modify 22.5.3.1 [optional.optional.general] as indicated:
namespace std { template<class T> class optional { public: […] template<class U = remove_cv_t<T>> constexpr explicit(see below) optional(U&&); […] template<class U = remove_cv_t<T>> constexpr optional& operator=(U&&); […] template<class U = remove_cv_t<T>> constexpr T value_or(U&&) const &; template<class U = remove_cv_t<T>> constexpr T value_or(U&&) &&; […] }; […] }
Modify 22.5.3.2 [optional.ctor] as indicated:
template<class U = remove_cv_t<T>> constexpr explicit(see below) optional(U&& v);-23- Constraints: […]
Modify 22.5.3.4 [optional.assign] as indicated:
template<class U = remove_cv_t<T>> constexpr optional& operator=(U&& v);-12- Constraints: […]
Modify 22.5.3.7 [optional.observe] as indicated:
template<class U = remove_cv_t<T>> constexpr T value_or(U&& v) const &;-15- Mandates: […]
[…]template<class U = remove_cv_t<T>> constexpr T value_or(U&& v) &&;-17- Mandates: […]
Modify 22.8.6.1 [expected.object.general] as indicated:
namespace std { template<class T, class E> class expected { public: […] template<class U = remove_cv_t<T>> constexpr explicit(see below) expected(U&& v); […] template<class U = remove_cv_t<T>> constexpr expected& operator=(U&&); […] template<class U = remove_cv_t<T>> constexpr T value_or(U&&) const &; template<class U = remove_cv_t<T>> constexpr T value_or(U&&) &&; […] }; […] }
Modify 22.8.6.2 [expected.object.cons] as indicated:
template<class U = remove_cv_t<T>> constexpr explicit(!is_convertible_v<U, T>) expected(U&& v);-23- Constraints: […]
Modify 22.8.6.4 [expected.object.assign] as indicated:
template<class U = remove_cv_t<T>> constexpr expected& operator=(U&& v);-9- Constraints: […]
Modify 22.8.6.6 [expected.object.obs] as indicated:
template<class U = remove_cv_t<T>> constexpr T value_or(U&& v) const &;-16- Mandates: […]
[…]template<class U = remove_cv_t<T>> constexpr T value_or(U&& v) &&;-18- Mandates: […]