Title
Constraint recursion for operator<=>(optional<T>, U)
Status
ready
Section
[optional.comp.with.t]
Submitter
Casey Carter

Created on 2021-06-07.00:00:00 last changed 1 month ago

Messages

Date: 2021-06-23.14:16:45

Proposed resolution:

This wording is relative to N4885.

  1. Modify [optional.syn], header <optional> synopsis, as indicated:

    […]
    // [optional.optional], class template optional
    template<class T>
    class optional;
    
    template<class T> 
      constexpr bool is-optional = false;               // exposition only
    template<class T> 
      constexpr bool is-optional<optional<T>> = true;   // exposition only
    
    […]
    // [optional.comp.with.t], comparison with T
    […]
    template<class T, class U> constexpr bool operator>=(const optional<T>&, const U&);
    template<class T, class U> constexpr bool operator>=(const T&, const optional<U>&);
    template<class T, three_way_comparable_with<T>class U>
      requires (!is-optional<U>) && three_way_comparable_with<T, U>
        constexpr compare_three_way_result_t<T, U>
          operator<=>(const optional<T>&, const U&);
    
    […]
    
  2. Modify [optional.comp.with.t] as indicated:

    template<class T, three_way_comparable_with<T>class U>
      requires (!is-optional<U>) && three_way_comparable_with<T, U>
        constexpr compare_three_way_result_t<T, U>
          operator<=>(const optional<T>& x, const U& v);
    

    -25- Effects: Equivalent to: return bool(x) ? *x <=> v : strong_ordering::less;

Date: 2021-06-15.00:00:00

[ 2021-06-23; Reflector poll ]

Set status to Tentatively Ready after five votes in favour during reflector poll.

Date: 2021-06-15.00:00:00

[ 2021-06-14; Improved proposed wording based on reflector discussion ]

Date: 2021-06-14.19:04:56

The three-way-comparison operator for optionals and non-optionals is defined in [optional.comp.with.t] paragraph 25:

template<class T, three_way_comparable_with<T> U>
  constexpr compare_three_way_result_t<T, U>
    operator<=>(const optional<T>& x, const U& v);

-25- Effects: Equivalent to: return bool(x) ? *x <=> v : strong_ordering::less;

Checking three_way_comparable_with in particular requires checking that x < v is well-formed for an lvalue const optional<T> and lvalue const U. x < v can be rewritten as (v <=> x) > 0. If U is a specialization of optional, this overload could be used for v <=> x, but first we must check the constraints…

The straightforward fix for this recursion seems to be to refuse to check three_way_comparable_with<T> when U is a specialization of optional. MSVC has been shipping such a fix; our initial tests for this new operator triggered the recursion.

Previous resolution [SUPERSEDED]:

This wording is relative to N4885.

  1. Modify [optional.syn], header <optional> synopsis, as indicated:

    […]
    // [optional.comp.with.t], comparison with T
    […]
    template<class T, class U> constexpr bool operator>=(const optional<T>&, const U&);
    template<class T, class U> constexpr bool operator>=(const T&, const optional<U>&);
    template<class T, three_way_comparable_with<T>class U>
      requires see below
        constexpr compare_three_way_result_t<T, U>
          operator<=>(const optional<T>&, const U&);
    
    […]
    
  2. Modify [optional.comp.with.t] as indicated:

    template<class T, three_way_comparable_with<T>class U>
      requires (!is-specialization-of<U, optional>) && three_way_comparable_with<T, U>
        constexpr compare_three_way_result_t<T, U>
          operator<=>(const optional<T>&, const U&);
    

    -?- The exposition-only trait template is-specialization-of<A, B> is a constant expression with value true when A denotes a specialization of the class template B, and false otherwise.

    -25- Effects: Equivalent to: return bool(x) ? *x <=> v : strong_ordering::less;

History
Date User Action Args
2021-06-23 14:16:45adminsetmessages: + msg11962
2021-06-23 14:16:45adminsetstatus: new -> ready
2021-06-14 19:04:56adminsetmessages: + msg11934
2021-06-12 12:53:03adminsetmessages: + msg11920
2021-06-07 00:00:00admincreate