为什么我需要包含<compare>头文件才能编译使用<=>运算符?

10
我知道技术上的答案是:因为标准规定如此。但我对其动机感到困惑:
我认为在默认<=>时没有任何"库"的东西:它可能会返回一些在std中技术上定义的类型,但从某种意义上说,它是一个"虚假的库"类型,因为编译器必须知道它,因为它必须能够使用auto返回类型来默认operator <=>(更不用说好的编译器中的错误消息指定了<compare>,因此这里明确存在语言<=>库链接)。
因此,我理解存在一些库功能可能需要我包含<compare>,但我不明白为什么默认<=>要求我包含该头文件,因为编译器无论如何都必须知道制作<=>所需的所有内容。
注意:我知道大多数情况下其他标准头文件将包含<compare>,这是关于语言/库设计的问题,而不是C++强制我写一行没有充分理由的额外代码的问题。

可能是类似的原因,就像您需要包含<new>才能使用放置new语法一样。 - eerorika
1
同样的情况也适用于<typeinfo>,它是使用typeid所必需的。 - DeiDei
2
@eerorika,有趣的是,您不需要包含<new>就可以使用默认的非放置operator new。因此,似乎没有技术上的理由强制用户包含这些内置操作的头文件。 - Brian Bi
“它是一种“假库”类型”,这样的东西并不存在。一个类型要么是编译器定义的基本类型,要么就不是。” - Nicol Bolas
@Brian new 是一种语言关键字,因此没有相应的头文件。但是用户可以重载 placement-new,其中 <new> 定义了默认的 placement-new - Remy Lebeau
除非有人参与了开发和演变与宇宙飞船运算符相关的规范的标准化过程,否则回答这个问题会有些困难。否则(甚至在那种情况下),答案几乎肯定是基于个人意见的,因为标准化过程是政治性的,提案可能存在缺陷需要时间来发现,完美的设计可能难以由编译器/库开发人员实现,但不完美的设计更容易实现。 - Peter
1个回答

7

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

嗯,<=> 返回的类型是非常真实的, 实际上是在 <compare> 中定义和实现的。就像初始化列表用于构造 std :: initializer_list<T> 一样,它是一个非常真实的类型,实际上是在 <initializer_list> 中定义的。还有 <typeinfo> 中的 typeinfo

这些比较类型 - std::strong_orderingstd::weak_orderingstd::partial_ordering (最初还有std::strong_equalitystd::weak_equality)- 本身具有非平凡的转换语义和其他操作,我们可能会在未来进行更改。它们将是非常特殊的语言类型,其中可转换性只沿着一个方向进行,但方式与继承非常不同(总排序类型仅有三个值,但部分排序类型有四个值...)。将这些定义为真正的库类型,然后将其交互指定为真正的库代码,实际上要容易得多。

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

有点像,但又不完全一样。编译器知道类型名称以及如何为基本类型生成值,但实际上并不需要更多的信息。返回类型的规则基本上是硬编码的,基于底层成员的<=>返回的类型,不需要了解这些实际类型的外观就可以完成。然后你只需要调用做任何事情的函数......

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


编译器知道类型的名称以及如何为基本类型生成值,但实际上除此之外它并不需要了解其他任何信息。据我所知,编译器还需要知道如何选择复合成员的最弱比较类别。 - NoSenseEtAl
1
@NoSense 我已经涵盖了那个问题,不是吗? - Barry
我不这么认为,因为编译器需要了解那些类型的许多信息,而不仅仅是名称。但这是一个观点问题...并且不值得大量打字。 我感觉基本的比较类别永远不会改变,可以在语言中硬编码。但至少我知道动机,所以我会接受这个答案。 - NoSenseEtAl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接