在这篇文章中,我碰到了这段晦涩的代码(仅以随意的方式呈现,就好像这是一段完全正常的C++代码):
struct Tree : std::vector<Tree> {};
接着创建两个树并进行比较(参见演示):
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
}
经过一些思考,我意识到这种比较似乎是合法的,但总是会产生错误的结果。
本文的主要想法是,由于C++17使用 std::lexicographical_compare
来实现向量的比较,该函数将两个序列中相应位置上的元素进行比较,并同时判断 a<b
和 b<a
的大小关系(请参见cpppreference上的“Possible implementation”部分),因此对于像上面的 Tree
这样深层次的结构,性能会随着深度的增加呈二次级别下降。实际上,情况确实如此。
本文还指出,三向比较不会出现这样的问题。但等等,这正是在 C++20 中引入的 operator<=>
。但是,这里有一个警告。
以下代码在 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&>(),
这是我的问题。这个编译错误是编译器的错误吗,还是这段代码实际上就有问题?如果这段代码有问题,那么它只在C++20中有问题,还是C++17和C++20都有问题?(后者意味着这段代码仅仅在C++17下偶然可以编译通过)。
compare_three_way
只比检查<=>
有更严格的要求:three_way_comparable_with
还需要equality_comparable
。 - Barry