You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于std::ranges::sort对仅支持partial_ordering且含运行时无序元素的范围排序结果是否明确的问询

问询:std::ranges::sort对仅支持partial_ordering且含运行时无序元素的范围排序结果是否明确?

嘿,最近在捣鼓C++20的范围排序时碰到个挠头的问题,想跟大家确认下:当我用std::ranges::sort去排序一个元素类型仅支持std::partial_ordering,而且范围里还存在运行时彼此无序的元素时,最终的排序结果是明确可预测的吗?

先给大家看个我写的测试用的结构体例子:

#include <cassert>
#include <algorithm>
#include <compare>
#include <iostream>
#include <optional>
#include <vector>

struct Foo {
    int val;
    bool is_unordered;
    Foo(int v, bool unord = false) : val(v), is_unordered(unord) {}
    friend auto operator<=>(Foo const& lhs, Foo const& rhs) {
        // 两个标记为无序的元素之间返回unordered
        if (lhs.is_unordered && rhs.is_unordered) {
            return std::partial_ordering::unordered;
        }
        // 其他情况按int的顺序比较
        return lhs.val <=> rhs.val;
    }
    friend bool operator==(Foo const& lhs, Foo const& rhs) {
        auto cmp = lhs <=> rhs;
        return cmp == std::partial_ordering::equal || cmp == std::partial_ordering::unordered;
    }
};

比如我创建这样一个容器:

std::vector<Foo> vec = {Foo(3), Foo(1, true), Foo(2), Foo(1, true)};
std::ranges::sort(vec);

这时候排序后的结果到底是确定的吗?我查了下相关规则,给大家捋一捋:

  • 首先,std::ranges::sort的核心要求是:比较器必须在元素上构成严格弱序(strict weak ordering)。这个要求是硬约束,标准里明确规定了,如果违反的话,程序行为就是未定义的。
  • 当你的元素比较返回std::partial_ordering::unordered时,这就打破了严格弱序的要求——严格弱序要求任意两个元素之间,要么a小于b,要么b小于a,要么两者等价,不存在“无序”这种第三种情况。
  • 所以如果直接用这种返回partial_ordering且存在运行时无序对的比较关系去调用std::ranges::sort,排序结果完全是不可预测的,可能每次运行都不一样,甚至可能出现奇怪的行为,标准不会给你任何保证。

那如果我就是要排序这类元素怎么办?其实很简单,自己写个比较器,把“无序”的情况转化为等价关系或者某种固定顺序,让比较器满足严格弱序就行。比如:

std::ranges::sort(vec, [](const Foo& a, const Foo& b) {
    auto cmp = a <=> b;
    // 把无序的元素视为等价,不进行交换
    if (cmp == std::partial_ordering::unordered) {
        return false;
    }
    return cmp == std::partial_ordering::less;
});

这时候比较器满足严格弱序了,排序后的结果就是明确可预测的了。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 13:38:06