C++20中用太空船运算符明确std::weak_ordering的语义问题
问题
我正在学习C++20中的std::strong_ordering和std::weak_ordering。根据文档,std::strong_ordering要求等价值不可区分,而std::weak_ordering则无此要求。
在研究std::weak_ordering(尤其是在太空船运算符<=>的语境下)时,我常遇到如下表示乘法表达式的示例结构体:
// Represents a multiplication expression, the result of which is (multiplicand * multiplier) struct Multiplication { int multiplicand; int multiplier; };
该结构体应属于弱排序,因为不同的被乘数和乘数组合可得到相同结果,即等价值可区分(如Multiplication{3, 2}、Multiplication{6, 1}和Multiplication{1, 6}都代表6)。
但比较该结构体的常规写法默认返回std::strong_ordering,因为乘法结果是int类型,属于强排序:
struct Multiplication { int multiplicand; int multiplier; // This returns std::strong_ordering by default auto operator<=>(Multiplication rhs) const { return (multiplicand * multiplier) <=> (rhs.multiplicand * rhs.multiplier); } };
请问在此场景下,是否需要显式指定返回类型为std::weak_ordering以保证语义准确?
回答
需要显式指定返回类型为std::weak_ordering来保证语义准确,核心原因如下:
- 语义匹配:
Multiplication类型完全符合弱排序的定义——存在值相等但可区分的实例(不同乘数组合得到相同乘积),这和std::weak_ordering的语义完全吻合;而std::strong_ordering要求相等实例必须完全不可区分,显然这里不满足该条件。 - 消除语义歧义:当前写法依赖int的
<=>返回std::strong_ordering,虽然能完成比较逻辑,但会给代码阅读者传递错误信号,让他们误以为相等的Multiplication实例是不可区分的。显式指定返回类型能清晰传达类型的排序特性,避免后续维护中的误解。 - 契合C++20设计初衷:太空船运算符的返回类型就是用来明确表达类型排序语义的,当类型自身的排序特性和底层比较值的排序特性不一致时,显式指定正确返回类型是符合C++20引入多种排序类型的核心设计意图的。
你可以通过两种方式修改代码:
方式一:手动返回对应排序值
#include <compare> struct Multiplication { int multiplicand; int multiplier; std::weak_ordering operator<=>(Multiplication rhs) const { const auto lhs_prod = multiplicand * multiplier; const auto rhs_prod = rhs.multiplicand * rhs.multiplier; if (lhs_prod == rhs_prod) { return std::weak_ordering::equivalent; } return lhs_prod < rhs_prod ? std::weak_ordering::less : std::weak_ordering::greater; } };
方式二:利用std::weak_order转换结果
#include <compare> struct Multiplication { int multiplicand; int multiplier; std::weak_ordering operator<=>(Multiplication rhs) const { return std::weak_order(multiplicand * multiplier, rhs.multiplicand * rhs.multiplier); } };
内容的提问来源于stack exchange,提问作者RaisinCrab
相关产品推荐
相关产品推荐

