Title
Comparison of optional<T> to T may be ill-formed
Status
new
Section
[optional.comp.with.t]
Submitter
Hewill Kang

Created on 2025-09-06.00:00:00 last changed 2 days ago

Messages

Date: 2025-09-15.16:11:08

Proposed resolution:

This wording is relative to N5014.

  1. Modify [optional.comp.with.t] as indicated:

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

    -1- Constraints: `U` is not a specialization of `optional`. The expression `*x == v` is well-formed and its result is convertible to `bool`.

    [Note 1: `T` need not be Cpp17EqualityComparable. — end note]

    -2- Effects: Equivalent to: `return x.has_value() ? *x == v : false;`

    if (x.has_value())
      return *x == v;
    return false;
    
    template<class T, class U> constexpr bool operator==(const T& v, const optional<U>& x);
    

    -3- Constraints: `T` is not a specialization of `optional`. The expression `v == *x` is well-formed and its result is convertible to `bool`.

    -4- Effects: Equivalent to: `return x.has_value() ? v == *x : false;`

    if (x.has_value())
      return v == *x;
    return false;
    
    template<class T, class U> constexpr bool operator!=(const optional<T>& x, const U& v);
    

    -5- Constraints: `U` is not a specialization of `optional`. The expression `*x != v` is well-formed and its result is convertible to `bool`.

    -6- Effects: Equivalent to: `return x.has_value() ? *x != v : true;`

    if (x.has_value())
      return *x != v;
    return true;
    
    template<class T, class U> constexpr bool operator!=(const T& v, const optional<U>& x);
    

    -7- Constraints: `T` is not a specialization of `optional`. The expression `v != *x` is well-formed and its result is convertible to `bool`.

    -8- Effects: Equivalent to: `return x.has_value() ? v != *x : true;`

    if (x.has_value())
      return v != *x;
    return true;
    
    template<class T, class U> constexpr bool operator<(const optional<T>& x, const U& v);
    

    -9- Constraints: `U` is not a specialization of `optional`. The expression *x < v is well-formed and its result is convertible to `bool`.

    -10- Effects: Equivalent to: return x.has_value() ? *x < v : true;

    if (x.has_value())
      return *x < v;
    return true;
    
    template<class T, class U> constexpr bool operator<(const T& v, const optional<U>& x);
    

    -11- Constraints: `T` is not a specialization of `optional`. The expression v < *x is well-formed and its result is convertible to `bool`.

    -12- Effects: Equivalent to: return x.has_value() ? v < *x : false;

    if (x.has_value())
      return v < *x;
    return false;
    
    template<class T, class U> constexpr bool operator>(const optional<T>& x, const U& v);
    

    -13- Constraints: `U` is not a specialization of `optional`. The expression *x > v is well-formed and its result is convertible to `bool`.

    -14- Effects: Equivalent to: return x.has_value() ? *x > v : false;

    if (x.has_value())
      return *x > v;
    return false;
    
    template<class T, class U> constexpr bool operator>(const T& v, const optional<U>& x);
    

    -15- Constraints: `T` is not a specialization of `optional`. The expression v > *x is well-formed and its result is convertible to `bool`.

    -16- Effects: Equivalent to: return x.has_value() ? v > *x : true;

    if (x.has_value())
      return v > *x;
    return true;
    
    template<class T, class U> constexpr bool operator<=(const optional<T>& x, const U& v);
    

    -17- Constraints: `U` is not a specialization of `optional`. The expression *x <= v is well-formed and its result is convertible to `bool`.

    -18- Effects: Equivalent to: return x.has_value() ? *x <= v : true;

    if (x.has_value())
      return *x <= v;
    return true;
    
    template<class T, class U> constexpr bool operator<=(const T& v, const optional<U>& x);
    

    -19- Constraints: `T` is not a specialization of `optional`. The expression v <= *x is well-formed and its result is convertible to `bool`.

    -20- Effects: Equivalent to: return x.has_value() ? v <= *x : false;

    if (x.has_value())
      return v <= *x;
    return false;
    
    template<class T, class U> constexpr bool operator>=(const optional<T>& x, const U& v);
    

    -21- Constraints: `U` is not a specialization of `optional`. The expression *x >= v is well-formed and its result is convertible to `bool`.

    -22- Effects: Equivalent to: return x.has_value() ? *x >= v : false;

    if (x.has_value())
      return *x >= v;
    return false;
    
    template<class T, class U> constexpr bool operator>=(const T& v, const optional<U>& x);
    

    -23- Constraints: `T` is not a specialization of `optional`. The expression v >= *x is well-formed and its result is convertible to `bool`.

    -24- Effects: Equivalent to: return x.has_value() ? v >= *x : true;

    if (x.has_value())
      return v >= *x;
    return true;
    
Date: 2025-09-06.00:00:00

When comparing an `optional` with its value type, the current wording specifies that the result is the ternary expression of `x.has_value() ? *x == v : false`, where `*x == v` returns a result that can be implicitly converted to `bool`.

However, when the result can also be constructed using `bool` (which is common), the ternary operation will be ill-formed due to ambiguity (demo):

#include <optional>

struct Bool {
  Bool(bool);
  operator bool() const;
};

struct S {
  Bool operator==(S) const;
};

int main() {
  return std::optional<S>{} == S{}; // fire
}
History
Date User Action Args
2025-09-15 16:11:08adminsetmessages: + msg15057
2025-09-06 00:00:00admincreate