Title
Heterogeneous comparisons in the standard library can result in ambiguities
Status
nad
Section
[tuple.rel][allocator.globals][unique.ptr.special] [util.smartptr.shared.cmp][time.duration.comparisons] [time.point.comparisons][scoped.adaptor.operators] [reverse.iter.cmp][move.iter.op.comp]
Submitter
Richard Smith

Created on 2015-02-07.00:00:00 last changed yesterday

Messages

Date: 2026-06-09.14:00:37

[ Brno 2026-06-09 Status changed: New → NAD. ]

The problematic and poorly-designed overloads in namespace `rel_ops` are deprecated and expected to be removed for C++29. If you do this to your type, you only have yourself to blame.

Date: 2015-02-07.00:00:00

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.

History
Date User Action Args
2026-06-09 14:00:37adminsetmessages: + msg16380
2026-06-09 14:00:37adminsetstatus: new -> nad
2015-02-07 00:00:00admincreate