Issue 3886: Monad mo' problems (original) (raw)
This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.
3886. Monad mo' problems
Section: 22.5.3.1 [optional.optional.general], 22.8.6.1 [expected.object.general] Status: WP Submitter: Casey Carter Opened: 2023-02-13 Last modified: 2024-11-28
Priority: 3
View all other issues in [optional.optional.general].
View all issues with WP 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.
That said, it would be peculiar to default the template type parameter of value_or to Tinstead 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 insteadremove_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.
[Wrocław 2024-11-23; Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N4928.
- Modify 22.5.3.1 [optional.optional.general] as indicated:
namespace std {
template
class optional {
public:
[…]
template<class U = remove_cv_t>
constexpr explicit(see below) optional(U&&);
[…]
template<class U = remove_cv_t> constexpr optional& operator=(U&&);
[…]
template<class U = remove_cv_t> constexpr T value_or(U&&) const &;
template<class U = remove_cv_t> constexpr T value_or(U&&) &&;
[…]
};
[…]
} 2. Modify 22.5.3.2 [optional.ctor] as indicated:
template<class U = remove_cv_t> constexpr explicit(see below) optional(U&& v);-23- Constraints: […] 3. Modify 22.5.3.4 [optional.assign] as indicated:
template<class U = remove_cv_t> constexpr optional& operator=(U&& v);-12- Constraints: […] 4. Modify 22.5.3.7 [optional.observe] as indicated:
template<class U = remove_cv_t> constexpr T value_or(U&& v) const &;-15- Mandates: […]
[…]
template<class U = remove_cv_t> constexpr T value_or(U&& v) &&;
-17- Mandates: […] 5. 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>
constexpr explicit(see below) expected(U&& v);
[…]
template<class U = remove_cv_t> constexpr expected& operator=(U&&);
[…]
template<class U = remove_cv_t> constexpr T value_or(U&&) const &;
template<class U = remove_cv_t> constexpr T value_or(U&&) &&;
[…]
};
[…]
} 6. Modify 22.8.6.2 [expected.object.cons] as indicated:
template<class U = remove_cv_t>
constexpr explicit(!is_convertible_v<U, T>) expected(U&& v);-23- Constraints: […] 7. Modify 22.8.6.4 [expected.object.assign] as indicated:
template<class U = remove_cv_t>
constexpr expected& operator=(U&& v);-9- Constraints: […] 8. Modify 22.8.6.6 [expected.object.obs] as indicated:
template<class U = remove_cv_t> constexpr T value_or(U&& v) const &;-16- Mandates: […]
[…]
template<class U = remove_cv_t> constexpr T value_or(U&& v) &&;
-18- Mandates: […]