In this article I've stumbled upon this obscure code (which is presented casually, like this is a totally normal C++ code):
struct Tree : std::vector<Tree> {};
Two trees are then created and compared (see the demo):
Tree tree(size_t h)
{
Tree s;
if (h > 0)
s.insert(s.end(), 2, tree(h - 1));
return s;
}
int main()
{
size_t h = 15;
Tree s1 = tree(h);
Tree s2 = tree(h);
clock_t t = clock();
s1 < s2;
double d = clock() - t;
d /= CLOCKS_PER_SEC;
std::cout << d << std::endl; // 4.1s
}
After some thinking, I've realized this comparison seems legal and will always yield false.
The idea of the article is that since C++17 implements comparisons of vectors with std::lexicographical_compare
, which compares corresponding elements a
and b
in two sequences as both a<b
and b<a
(see "Possible implementation" section on cpppreference), the performance for deep structures like the Tree
above will degrade quadratically on the depth. And indeed it does.
The article also says that three-way comparison does not have such a problem. But wait, that's exactly what emerged in C++20 with operator<=>
. But here is the caveat.
This code does not compile in C++20:
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/11.0.1/../../../../include/c++/11.0.1/compare:914:35: fatal error: recursive template instantiation exceeded maximum depth of 1024
= decltype(__detail::__synth3way(std::declval<_Tp&>(),
Here is my question. Is this compile error a bug in the compiler, or is this code actually ill-formed? If the code is ill-formed, is it so only for C++20 or for both C++17 and C++20? (The latter would imply that this code compiles under C++17 only by chance).
compare_three_way
just has stricter requirements than simply checking for<=>
:three_way_comparable_with
also requiresequality_comparable
. – Possessive