This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++17 status.

### 2934. `optional<const T>` doesn't compare with `T`

Section: 20.6.8 [optional.comp.with.t] Status: C++17 Submitter: Ville Voutilainen Opened: 2017-02-17 Last modified: 2021-06-06

Priority: Not Prioritized

View all other issues in [optional.comp.with.t].

View all issues with C++17 status.

Discussion:

Consider:

>     optional<const int> x = 42;
>     int y = 666;
>     x == y; // ill-formed

The comparison is ill-formed, because in [optional.comp_with_t]/1,

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

the `T` is deduced to be both `const int` and `int`, which is ill-formed.

Since it became apparent that the root cause of this issue is also causing difficulties with e.g. comparing `optional<string>` with literals etc., here's a p/r that

1. adds requirements for `optional`'s comparisons with `T`

2. turns `optional`-`optional` comparisons into two-template-parameter templates, allowing comparing mixed optionals

3. turns `optional`-`T` comparisons into two-template-parameter templates, allowing comparing optionals with `T` and types comparable with `T`

[Kona 2017-02-28]

Accepted as Immediate to avoid having break ABI later.

Proposed resolution:

This wording is relative to N4640.

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

   >     […]

   >     // 20.6.6 [optional.relops], relational operators
   >     template <class T, class U>
   >     constexpr bool operator==(const optional<T>&, const optional<TU>&);
   >     template <class T, class U>
   >     constexpr bool operator!=(const optional<T>&, const optional<TU>&);
   >     template <class T, class U>
   >     constexpr bool operator<(const optional<T>&, const optional<TU>&);
   >     template <class T, class U>
   >     constexpr bool operator>(const optional<T>&, const optional<TU>&);
   >     template <class T, class U>
   >     constexpr bool operator<=(const optional<T>&, const optional<TU>&);
   >     template <class T, class U>
   >     constexpr bool operator>=(const optional<T>&, const optional<TU>&);

   >     […]

   >     //  [optional.comp_with_t], comparison with T
   >     template <class T, class U> constexpr bool operator==(const optional<T>&, const TU&);
   >     template <class T, class U> constexpr bool operator==(const TU&, const optional<T>&);
   >     template <class T, class U> constexpr bool operator!=(const optional<T>&, const TU&);
   >     template <class T, class U> constexpr bool operator!=(const TU&, const optional<T>&);
   >     template <class T, class U> constexpr bool operator<(const optional<T>&, const TU&);
   >     template <class T, class U> constexpr bool operator<(const TU&, const optional<T>&);
   >     template <class T, class U> constexpr bool operator<=(const optional<T>&, const TU&);
   >     template <class T, class U> constexpr bool operator<=(const TU&, const optional<T>&);
   >     template <class T, class U> constexpr bool operator>(const optional<T>&, const TU&);
   >     template <class T, class U> constexpr bool operator>(const TU&, const optional<T>&);
   >     template <class T, class U> constexpr bool operator>=(const optional<T>&, const TU&);
   >     template <class T, class U> constexpr bool operator>=(const TU&, const optional<T>&);

2. Modify 20.6.6 [optional.relops] as indicated:

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

   > > […]

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

   > > […]

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

   > > […]

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

   > > […]

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

   > > […]

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

   > > […]

3. Modify [optional.comp_with_t] as indicated:

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

   > > -?- Requires: The expression `*x == v` shall be well-formed and its result shall be convertible to `bool`. [Note: `T` need not be `EqualityComparable`. — end note]

   > > -1- Effects: Equivalent to: `return bool(x) ? *x == v : false;`

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

   > > -?- Requires: The expression `v == *x` shall be well-formed and its result shall be convertible to `bool`.

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

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

   > > -?- Requires: The expression `*x != v` shall be well-formed and its result shall be convertible to `bool`.

   > > -3- Effects: Equivalent to: `return bool(x) ? *x != v : true;`

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

   > > -?- Requires: The expression `v != *x` shall be well-formed and its result shall be convertible to `bool`.

   > > -4- Effects: Equivalent to: `return bool(x) ? v != *x : true;`

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

   > > -?- Requires: The expression `*x < v` shall be well-formed and its result shall be convertible to `bool`.

   > > -5- Effects: Equivalent to: `return bool(x) ? *x < v : true;`

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

   > > -?- Requires: The expression `v < *x` shall be well-formed and its result shall be convertible to `bool`.

   > > -6- Effects: Equivalent to: `return bool(x) ? v < *x : false;`

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

   > > -?- Requires: The expression `*x <= v` shall be well-formed and its result shall be convertible to `bool`.

   > > -7- Effects: Equivalent to: `return bool(x) ? *x <= v : true;`

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

   > > -?- Requires: The expression `v <= *x` shall be well-formed and its result shall be convertible to `bool`.

   > > -8- Effects: Equivalent to: `return bool(x) ? v <= *x : false;`

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

   > > -?- Requires: The expression `*x > v` shall be well-formed and its result shall be convertible to `bool`.

   > > -9- Effects: Equivalent to: `return bool(x) ? *x > v : false;`

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

   > > -?- Requires: The expression `v > *x` shall be well-formed and its result shall be convertible to `bool`.

   > > -10- Effects: Equivalent to: `return bool(x) ? v > *x : true;`

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

   > > -?- Requires: The expression `*x >= v` shall be well-formed and its result shall be convertible to `bool`.

   > > -11- Effects: Equivalent to: `return bool(x) ? *x >= v : false;`

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

   > > -?- Requires: The expression `v >= *x` shall be well-formed and its result shall be convertible to `bool`.

   > > -12- Effects: Equivalent to: `return bool(x) ? v >= *x : true;`