2472. Heterogeneous comparisons in the standard library can result in ambiguities

Section: 22.4.9 [tuple.rel], [allocator.globals], [unique.ptr.special], [util.smartptr.shared.cmp], 29.5.7 [time.duration.comparisons], 29.6.7 [time.point.comparisons], 20.5.5 [scoped.adaptor.operators], [reverse.iter.cmp], [move.iter.op.comp] Status: New Submitter: Richard Smith Opened: 2015-02-07 Last modified: 2021-06-06 18:38:24 UTC

Priority: 3

View other active issues in [tuple.rel].

View all other issues in [tuple.rel].

View all issues with New status.


The standard library specifies a lot of heterogeneous comparison operators. For instance:

template<class... TTypes, class... UTypes>
constexpr bool operator!=(const tuple<TTypes...>&, const tuple<UTypes...>&);

This has an unfortunate consequence:

#include <tuple>
#include <utility>

using namespace std::rel_ops;
std::tuple<int> a(0);
bool b = a != a;

The last line here is ill-formed due to ambiguity: it might be rel_ops::operator!=, and it might be the heterogeneous tuple operator!=. These are not partially ordered, because they have different constraints: rel_ops requires the types to match, whereas the tuple comparison requires both types to be tuples (but not to match). The same thing happens for user code that defines its own unconstrained 'template<typename T> operator!=(const T&, const T&)' rather than using rel_ops.

One straightforward fix would be to add a homogeneous overload for each heterogeneous comparison:

template<class... TTypes>
constexpr bool operator!=(const tuple<TTypes...>&, const tuple<TTypes...>&);

This is then unambiguously chosen over the other options in the preceding case. FWIW, libstdc++ already does this in some cases.

Proposed resolution: