我有一个情况,结构类型需要非默认
operator<=>
- 只是在定义对象顺序时并非所有字段都很重要。
struct A
{
int a;
int b; // not important when ordering
int c;
constexpr std::strong_ordering operator<=>(const A& rhs) const
{
if (const auto res = a<=>rhs.a; res != 0) return res;
return c<=>rhs.c;
}
};
令我惊讶的是,我无法使用这种类型的容器作为
std::ranges::sort
的参数:
std::array<A, 100> aa{};
std::ranges::sort(aa);
我在最新的 gcc (14) 和 clang (19) 上检查了它,它基本上声称该范围不可排序,因为
std::invocable_v<std::ranges::less&, A&, A&>
不正确。
请参阅godbold 链接
更多观察:
std::sort(aa.begin(), aa.end());
)operator==
=default
)operator<=>
这是编译器错误、C++ 标准错误还是一些奇怪的 C++ 规则在这里发挥作用并且应该是这样? 如果最后一个选项是正确的 - 你能为这种行为提供理由吗?
更新:
从评论看来,
std::ranges::less{}(A{}, A{})
不仅需要operator<
(源自operator<=>
),还需要无法从非默认operator==
派生的operator<=>
,所以会出现错误。
但是还有一个问题 - 为什么
std::ranges::less
需要 operator==
?
还有评论中更好的例子:link
一般来说,
std::ranges
算法比std::
算法受到更多限制。目标不是提供算法所需的绝对最小操作集,而是提供一个有凝聚力的操作模型。
在这种情况下,所有基于排序的算法都需要排序和相等。在其他几种语言中,如果不提供平等性,您甚至无法选择排序。这是较弱的功能,因此两者兼有是有意义的。
因此
std::ranges::sort(aa)
失败,因为虽然 A
提供排序 (<=>
),但它不提供相等 (==
)。所以你的选择是:
==
运算符(同样不会查看 b
),或者 sort
提供自定义排序(这不会查看 b
)。请注意,范围算法do支持投影,因此后者可能看起来像:
std::ranges::sort(aa, std::ranges::less(), [](A const& a){ return std::tie(a.a, a.c); });
您可以将其包裹在像这样的可爱适配器中:
std::ranges::sort(aa, std::ranges::less(), by(&A::a, &A::c));