#include <tuple>
struct X {
int i = 0;
friend constexpr bool operator<(const X &l, const X &r) noexcept {
return l.i < r.i;
}
};
struct Y {
int i = 0;
constexpr operator bool() const noexcept {
return i != 0;
}
friend constexpr bool operator<(const Y &l, const Y &r) noexcept {
return l.i < r.i;
}
};
int main() {
constexpr X a{1}, b{2};
static_assert(std::tie(a) < std::tie(b));
constexpr Y c{1}, d{2};
static_assert(c < d);
// assert failed
// static_assert(std::tie(c) < std::tie(d));
return 0;
}
Updating: When compiling with C 20.
Line static_assert(std::tie(c) < std::tie(d));
will fail. It turns out that when comparing c
and d
, operator bool
is called instead of operator<
. Why would operator bool
get involved in the first place?
I find this quite surprising. Is this intended or a bug? Any help is welcome, thanks.
CodePudding user response:
When comparing two tuple<T>
s, named t1
and t2
, the operator<=>
overload for tuple
will use get<0>(t1) <=> get<0>(t2)
to compare elements when type T
satisfies three_way_comparable
; otherwise, it will use operator<
.
Since Y
is implicitly convertible to bool
, this makes y <=> y
a valid expression and satisfies three_way_comparable
, such that std::tie(c) < std::tie(d)
(unexpectedly) invokes bool(c) <=> bool(d)
in your example.