std::ranges::sort 不适用于非默认运算符<=>?

问题描述 投票:0回答:1

我有一个情况,结构类型需要非默认

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 链接

更多观察:

  1. 它适用于 std::sort (
    std::sort(aa.begin(), aa.end());
    )
  2. 添加非默认值时有效
    operator==
  3. 并且它可以使用默认值(
    =default
    operator<=>

这是编译器错误、C++ 标准错误还是一些奇怪的 C++ 规则在这里发挥作用并且应该是这样? 如果最后一个选项是正确的 - 你能为这种行为提供理由吗?


更新:

从评论看来,

std::ranges::less{}(A{}, A{})
不仅需要
operator<
(源自
operator<=>
),还需要无法从非默认
operator==
派生的
operator<=>
,所以会出现错误。

但是还有一个问题 - 为什么

std::ranges::less
需要
operator==

还有评论中更好的例子:link

c++ sorting language-lawyer c++20 std-ranges
1个回答
0
投票

一般来说,

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));
© www.soinside.com 2019 - 2024. All rights reserved.