A change was made in C++20, and I'm having a hard time finding where in the standard I can go look to learn that this change happened. Would someone please quote me the section of the standard that tells me this will happen?
I am aware of this question: Breaking change in std::tuple lexicographic comparison in C++20 with conversion operators?
but it does not answer the question about where I can find this out in the standard.
With both gcc 11.2 and clang this code prints out 01
(the expected result) with -std=c++17
and 10
with -std=c++20
. Is this correct behavior? If it is, where in the standard should I look to find out why?
#include <iostream>
struct S {
int a;
S( int a ) : a( a ){ }
operator
int() const {
return a;
}
friend bool
operator<( const S & lhs, const S & rhs ){
return lhs.a > rhs.a;
}
};
int
main(){
std::pair< int, S > p1{ 0, 1 }, p2{ 0, 2 };
std::cout << (p1 < p2) << (p2 < p1) << std::endl;
}
In C++17, [pairs.spec] defined all the relational operators. For instance, operator<
was specified as:
template <class T1, class T2> constexpr bool operator<(const pair<T1, T2>& x, const pair<T1, T2>& y);
Returns:
x.first < y.first || (!(y.first < x.first) && x.second < y.second)
.
In C++20, with the adoption of <=>
, this looks a bit different. Also in [pairs.spec]:
template<class T1, class T2> constexpr common_comparison_category_t<synth-three-way-result<T1>, synth-three-way-result<T2>> operator<=>(const pair<T1, T2>& x, const pair<T1, T2>& y);
Effects: Equivalent to:
if (auto c = synth-three-way(x.first, y.first); c != 0) return c; return synth-three-way(x.second, y.second);
Where synth-three-way(x, y)
will do x <=> y
if possible, otherwise do x < y
and then y < x
(see [expos.only.func]).
The issue here is that x <=> y
for your type is actually valid, but does something different from x < y
, so you get a different result.