std::strong_ordering 是 C++20 三向比较中最常用也最易误用的返回类型,要求值相等即完全可互换;它由编译器在所有成员均支持强序时自动推导,但含 float、指针、mutable 或时间戳等成员会降级为 std::partial_ordering 或 std::weak_ordering。

直接说结论:std::strong_ordering 是 C++20 三向比较中**最常用、最严格、也最容易误用**的返回类型——它要求两个对象“值相等”就必须“完全可互换”,一旦成员语义不满足强相等(比如含指针、缓存字段、时间戳),operator = default 就可能产生逻辑错误。
什么时候 std::strong_ordering 会自动出现?
编译器在生成默认 operator 时,只要所有非静态数据成员都支持强序比较,就推导出 std::strong_ordering。这不是你选的,是它“算出来”的。
-
int、char、enum class、std::string(默认)这些类型本身返回std::strong_ordering - 结构体如
struct Point { int x, y; },因两个int都是强序,所以auto operator(const Point&) const = default;返回std::strong_ordering - 但只要加一个
float z;,整个结构体的默认就变成std::partial_ordering(因为float允许 NaN)
为什么不能对所有类型都用 std::strong_ordering?
它不是“更高级”的选项,而是一种**契约承诺**:你声明返回 std::strong_ordering,就等于告诉标准库和使用者——“这两个对象如果 ==,那它们在任何上下文中行为都一致”。这在现实中常不成立。
- 含指针成员的类:两个对象内容相同,但指针地址不同 →
==可能为 true,但它们不可互换(比如指针用于缓存键) - 含
mutable缓存字段的类:两次调用==可能因缓存状态不同而结果不一致 - 含
std::chrono::steady_clock::time_point的类:时间戳几乎不可能相等,但强行用strong_ordering会让a == b成为“数学上等价”的断言,而非“业务上视为相等”
手动指定返回类型时,std::strong_ordering 怎么写才安全?
你不能“强制返回 std::strong_ordering”来掩盖语义缺陷;但可以显式定义并控制比较逻辑,前提是你的业务确实满足强序要求。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
例如,一个纯数据结构体,且明确禁止 NaN、指针、可变状态:
#include <compare>
struct Vec2 {
float x, y;
auto operator<=>(const Vec2& other) const -> std::strong_ordering {
// 注意:这里必须自己处理 NaN,否则行为未定义
if (std::isnan(x) || std::isnan(y) || std::isnan(other.x) || std::isnan(other.y))
throw std::domain_error("NaN not allowed in Vec2");
if (auto cmp = x <=> other.x; cmp != 0) return cmp;
return y <=> other.y;
}
};
- 返回类型声明为
-> std::strong_ordering是显式契约,编译器会检查函数体是否只返回less/equal/greater - 不能直接写
return x <=> other.x;—— 因为float <=> float返回的是std::partial_ordering,类型不匹配 - 必须用
if+return显式降级,或用std::compare_strong_order_fallback(C++20 提供的辅助)
容易被忽略的关键点
很多人以为只要写了 = default 就万事大吉,其实最危险的恰恰是“默认生成却没看懂返回类型”。
-
std::strong_ordering::equal和operator==不是同一回事:前者是排序等价,后者是用户自定义的相等语义;若你重载了operator==但没同步调整,两者可能不一致 - STL 容器如
std::set或算法如std::sort在 C++20 下会优先使用,若返回类型与实际需求错配(比如该用weak_ordering却用了strong_ordering),可能导致去重异常或排序不稳定 - 调试时别只看
a < b是否成立——要查a <=> b的具体返回值,用result == std::strong_ordering::equal而不是result == 0,后者在partial_ordering下不安全

















