为什么我需要包含 <compare> 头来让 <=> 编译?

NoS*_*tAl 7 c++ spaceship-operator c++20

我知道技术答案是:因为标准是这样说的。

但我对动机感到困惑:

我什么也看不到“库”中违约的<=>:它可能会返回在技术上定义了一些类型std,但它在某种意义上是一种“假库”类型的编译器必须知道关于它,因为它必须能够默认operator <=>auto返回类型(更不用说好的编译器中的错误消息指定了<compare>所以很明显这里有一个语言<=>库链接)。

所以我知道有些库功能可能需要我包含,<compare>但我不明白为什么默认设置<=>需要我包含该头文件,因为编译器无论如何都必须知道制作<=>.

注意:我知道大多数时候其他一些标准头文件会包含<compare>,这是一个关于语言/库设计的问题,而不是 C++ 强迫我在没有充分理由的情况下编写的额外行。

Bar*_*rry 7

它可能返回某种在 std 中技术上定义的类型,但从某种意义上来说它是一个“假库”类型

嗯,返回非常真实的<=>类型,这些类型实际上是在其中定义和实现的。与使用初始值设定项列表构造 a 的方式相同,它实际上是在 中定义的真实类型。并在.<compare>std::initializer_list<T><initializer_list>typeinfo<typeinfo>

这些比较类型 - std::strong_orderingstd::weak_ordering、 and std::partial_ordering(最初也是std::strong_equalityand std::weak_equality) - 本身具有重要的转换语义和在其上定义的其他操作,我们将来可能希望更改。它们确实是非常特殊的语言类型,其中可转换性仅在一个方向上进行,但在某种程度上与继承非常不同(总排序类型只有三个值,但部分排序类型有四个值......)。将它们定义为真正的库类型,然后将它们的交互指定为真正的库代码确实要容易得多。

编译器必须知道它,因为它必须能够默认operator<=>返回auto类型

有点像,但不是真的。编译器知道类型的名称是什么,以及如何为基本类型生成它们的值,但实际上不需要知道更多的东西。返回类型的规则基本上是基于底层成员返回的类型进行硬编码的<=>,不需要知道这些实际类型是什么样的。然后你只需调用执行......任何操作的函数。

必须包含标头的成本是键入#include <compare>然后解析它。编译器必须综合这些类型的成本是必须为每个 TU 付出的成本,无论它是否进行任何三向比较。另外,如果/当我们想要更改这些类型时,更改库类型比更改语言类型更容易。