#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.
