三路比较运算符operator是C++20引入的“太空船运算符”,用一个函数定义全部比较关系;可default生成或手动返回std::strong_ordering等,但显式定义operator==会阻止==的隐式合成。

三路比较运算符 operator 是什么
它是 C++20 引入的“太空船运算符”,用一个函数同时定义 、==、> 等全部比较关系,避免手写六个比较运算符的重复劳动。
怎么写一个基本的 operator
最常见写法是返回 std::strong_ordering(或 std::weak_ordering、std::partial_ordering),编译器会自动合成其余比较操作符(前提是没显式定义它们)。
struct Point {
int x, y;
auto operator<=>(const Point& other) const = default; // 编译器自动生成
};
也可以手动实现:
struct Version {
int major, minor, patch;
auto operator<=>(const Version& v) const {
if (auto cmp = major <=> v.major; cmp != 0) return cmp;
if (auto cmp = minor <=> v.minor; cmp != 0) return cmp;
return patch <=> v.patch;
}
};
-
= default仅在所有成员都支持且可平凡比较时安全 - 手动实现中,用
if (auto cmp = ...; cmp != 0) return cmp是惯用模式,避免多次计算 - 返回类型选
std::strong_ordering表示全序(如整数、字符串),std::partial_ordering用于可能有NaN的浮点场景
为什么不能随便混用 == 和
如果类里显式定义了 operator==,即使写了 operator,编译器也不会自动生成 == —— 它会优先用你写的 ==,而 仍只负责大小关系。
立即学习“C++免费学习笔记(深入)”;
- 若只定义
operator,==会被隐式合成(等价于a b == 0) - 但一旦你加了
bool operator==(const T&) const { ... },哪怕逻辑完全一样,==就不再由推导 - 这会导致行为不一致:比如自定义
==忽略大小写,但按字节比较,那a == b为真时a b可能非零
容易被忽略的兼容性细节
operator 不会自动让类支持 std::sort 或 std::map —— 这些容器仍依赖 operator,而它默认由 合成;但如果你禁用了合成(比如显式删掉 operator),就会编译失败。
- 检查是否真生成了
operator:用static_assert(std::is_invocable_v) - 模板代码中(如
std::ranges::sort),传入自定义比较器更稳妥,别盲目依赖合成 - 第三方库若用 SFINAE 检测
operator==,而你只靠合成,可能因未实例化而失败
真正省事的前提是:所有成员类型本身支持三路比较,且你不插手任何一个比较运算符的显式定义 —— 多一动,就得多一分验证。











