在 C++20 中,您可以获得 三向比较(运算符
<=>
),它会自动“生成”默认比较(如果提供):
struct A {
// You only need to implement a single operator.
std::strong_ordering operator<=>(const A&) const;
};
// Compiler generates 4 relational operators (you need to default the
// three-way comparison operator to get == and !=).
A to1, to2;
if (to1 > to2) { /* ... */ } // ok
if (to1 <= to2) { /* ... */ } // ok, single call to <=>
与
std::rel_ops
相比,三向比较有多种优点,这可能就是不推荐使用 std::rel_ops
运算符的原因。在我头顶上:
它更通用,因为根据
operator<=>
(std::strong_ordering
,std::weak_ordering
,...)的返回类型,仅生成相关运算符。有关更多信息,请参阅 <compare>
标题。您不会通过执行
using namespace std::rel_ops
带来一堆模板化运算符重载。您可以要求编译器默认生成三向运算符(
auto operator<=>(A const&) = default
)——这基本上会生成基类和非静态数据成员的字典比较,此外,它还会推导出正确的类型如果返回类型为 auto
.背后的理由是什么?
rel_ops
已被 宇宙飞船(比较)操作员的库支持弃用。论文没有列出任何动机,但它确实出现在太空飞船论文中:
这包含命名空间
,因此我们建议也删除(或弃用)std::rel_ops
。std::rel_ops
论文中提到了四个原因(包括正确性和性能)。但这两篇论文中都没有提到的一个重要问题是
std::rel_ops
只是......不起作用。经验法则是使用 ADL 找到操作员。 rel_ops
不会为您提供 ADL 可查找的运算符,它只是声明不受约束的函数模板,例如:
namespace std {
namespace rel_ops {
template< class T >
bool operator!=( const T& lhs, const T& rhs )
{
return !(lhs == rhs);
}
}
}
因此使用如下算法:
struct X { ... };
bool operator<(X const&, X const&) { ... };
std::sort(values.begin(), values.end(), std::greater<>{});
根本行不通,除非你确保:
#include <utility>
using namespace std::rel_ops;
在第一次包含时在任何地方都相当一致,以确保这些运算符在您可能调用的每个函数模板的定义点都可见。
所以
operator<=>
绝对优越:
<=>
)而不是两个(==
和<
)= default
)C++20 提供了三路比较,因此唯一的比较将被弃用。