Title
optional::value_or should never return a cv-qualified type
Status
new
Section
[optional.observe]
Submitter
Casey Carter

Created on 2020-04-02.00:00:00 last changed 22 months ago

Messages

Date: 2023-02-10.09:41:36

Proposed resolution:

This wording is relative to N4928.

  1. Modify [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&&) &&;
    […]
    
  2. Modify [optional.observe] as indicated:

    [Drafting note: The two removals of the && in is_convertible_v<U&&, T> below is a simplification to restore consistency with the wording for expected::value_or.]

    template<class U> constexpr remove_cv_t<T> value_or(U&& v) const &;
    

    -?- Let R be remove_cv_t<T>.

    -15- Mandates: is_copy_constructible_v<T> is_convertible_v<const T&, R> && is_convertible_v<U&&, TR> is 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 R be remove_cv_t<T>.

    -17- Mandates: is_move_constructible_v<T> is_convertible_v<T, R> && is_convertible_v<U&&, TR> is true.

    -18- Effects: Equivalent to:

    return bool(*this) ? std::move(**this) : static_cast<TR>(std::forward<U>(v));
    

  3. Modify [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&&) &&;
    […]
    
  4. Modify [expected.object.obs] as indicated:

    template<class U> constexpr remove_cv_t<T> value_or(U&& v) const &;
    

    -?- Let R be remove_cv_t<T>.

    -16- Mandates: is_copy_constructible_v<T> is_convertible_v<const T&, R> && is_convertible_v<U, TR> is 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 R be remove_cv_t<T>.

    -18- Mandates: is_move_constructible_v<T> is_convertible_v<T, R> && is_convertible_v<U, TR> is true.

    -19- Returns: has_value() ? std::move(**this) : static_cast<TR>(std::forward<U>(v)).

Date: 2023-02-09.00:00:00

[ 2023-02-09 Casey improves wording and expands to cover expected::value_or ]

Since expected was modeled on optional, it has the same issue.

Date: 2020-04-18.00:00:00

[ 2020-04-18 Issue Prioritization ]

Priority to 3 after reflector discussion.

Previous resolution [SUPERSEDED]:

This wording is relative to N4861.

  1. Modify [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&&) &&;
    […]
    
  2. Modify [optional.observe] as indicated:

    template<class U> constexpr remove_cv_t<T> value_or(U&& v) const&;
    

    -?- Let R be remove_cv_t<T>.

    -17- Mandates: is_copy_constructible_v<T>is_convertible_v<const T&, R> && is_convertible_v<U&&, T> is 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 R be remove_cv_t<T>.

    -19- Mandates: is_move_constructible_v<T>is_convertible_v<T, R> && is_convertible_v<U&&, T> is true.

    -20- Effects: Equivalent to:

    return bool(*this) ? std::move(**this) : static_cast<TR>(std::forward<U>(v));
    

Date: 2020-04-02.00:00:00

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.

History
Date User Action Args
2023-02-10 09:41:36adminsetmessages: + msg13330
2020-04-18 12:19:25adminsetmessages: + msg11223
2020-04-05 16:33:53adminsetmessages: + msg11198
2020-04-02 00:00:00admincreate