为什么引入 std::ranges::less?

Why was std::ranges::less introduced?

cppreference on std::ranges::less 上,在 notes 中我们可以看到:

Unlike std::less, std::ranges::less requires all six comparison operators <, <=, >, >=, == and != to be valid (via the totally_ordered_with constraint).

但是……为什么?为什么我们要使用 std::ranges::less{} 而不是 std::less{}?仅当定义了其他比较运算符而不仅仅是 < 时,我们才希望 less{} 的实际情况是什么?

据我所知,基于 proposal 的想法只是简化函数对象的设计。 std::less是模板class,需要模板参数,代表同质比较。可以省略此模板参数以默认为 std::less<void>,这允许异构比较。争论似乎是同构案例是不必要的,因为它可以通过异构方法很好地处理,因此设计可以大大简化并且根本不需要 class 模板。

至于为什么需要 operator< 以外的其他运算符,我不太确定。我最好的猜测是,这只是在 C++ 中定义两种可能不同的类型之间的总顺序的一部分。

What is the practical situation in which we want to less{} only if there are other comparison operators defined, not only the < one?

并不是关于 Ranges 库的所有内容都完全基于“实用”。其中大部分是关于使语言和库具有逻辑意义。

作为语言特征的概念使标准库有机会定义有意义的对象特征组合。说一个类型有一个 operator< 从纯实用的角度来看是有用的,因为它告诉您它可以使用哪些操作。但它并没有真正说明类型的任何意义。

如果一个类型是完全有序的,那么这在逻辑上意味着您可以使用任何比较运算符来比较该类型的两个对象。在全序的思想下,a < bb > a是等价的语句。因此,如果代码仅限于提供总顺序的类型,那么应该允许该代码使用任一语句是有道理的。

ranges::less::operator() 使用 < 以外的任何运算符。但是此功能仅限于对 totally_ordered 概念进行建模的类型。存在此约束是因为 ranges::lessfor:比较完全有序的类型。它可以有一个更窄的约束,但这将丢弃总排序提供的任何意义。

它还可以防止您向用户公开任意实施细节。例如,假设您有一个采用某种类型 T 的模板,并且您想在基于 ranges::less 的操作中使用 T。如果您将此模板限制为仅具有 operator<,那么您实际上已将您的实现置于约束中。您不再有实现在内部切换到 ranges::greater 的自由。然而,如果您将 std::totally_ordered 放入您的约束中,您将让用户清楚他们需要做什么,同时让您可以自由地使用您需要的任何仿函数。

并且由于存在 operator<=> 并且可以很容易地在一个函数中实现排序运算符,因此没有 实用的 缺点。嗯,除了必须在 C++17 和 C++20 上编译的代码。

从本质上讲,您不应该通过只写 operator< 来编写“有序”的类型。