c++ 操作符 < = >
对于所有关系运算符,没有等价的规则说明定义运算符 <
就足够了。
但是,您只需定义运算符 < = >
。
实际上,以下内容足以使程序员使用所有的比较器:
class Value {
private: long id; ...
public:
constexpr Value(long i) noexcept :id{i} {
}
// enable use of all equality and relutional operators:
auto operator<=> (const Value& rhs) const = default; };
通常,运算符 = =
负责相等运算符,而运算符 < = >
负责关系运算符。但是,通过声明一个操作符 < = >
with = default,我们使用一个特殊的规则,即默认的成员操作符 < = >
:
class Value {
auto operator<=> (const Value& rhs) const = default; };
生成一个对应的成员操作符 = =
,这样我们就可以有效地得到:
class Value {
...
auto operator<=> (const Value& rhs) const =default;
auto operator== (const Value& rhs) const =default;
//implicitly generated };
这样做的结果是,两个运算符都使用它们的默认实现,即逐个成员比较对象。这意味着类中成员的顺序很重要。
因此,与
class Value {
...
auto operator<=> (const Value& rhs) const = default; };
我们可以使用所有六个比较运算符。
此外,即使将运算符声明为成员函数,生成的运算符
· 如果在编译时可以比较成员,则为 conexpr
· 由于重写,如果定义了相应的隐式类型转换,则还支持第一个操作数的隐式类型转换(尽管它不作为参数传递)
· 如果没有使用比较结果可能会发出警告(这取决于编译器)
这反映了在一般情况下,运算符= =
和运算符< = >
关注不同但相关的事情:
运算符 = =
定义了相等性,可以由相等操作符 = =
和! =
使用。
· 运算符 < = >
定义了顺序,可以由关系运算符 <
、 < =
、 >
和> =
使用。
为了对生成的比较运算符有更多的控制权,您可以自己定义运算符 = = 和运算符 < = > ,例如:
class Value{
private: long id; ...
public:
constexpr Value(long i) noexcept : id{i} {
} ...
//for equality operators:
bool operator== (const Value& rhs) const { return id == rhs.id;
// defines equality (==and!=) }
// forrelutional operators:
auto operator<=> (const Value& rhs) const { return id <=> rhs.id;
//defines ordering(<,<=,>,and>=) }
};
这些基本运算符的工作方式是,如果一个表达式使用其中一个比较运算符,并且没有找到匹配的直接定义,那么该表达式将被重写,以便可以使用这些运算符。对应于相等运算符的重写调用,重写还可能改变关系操作数的顺序,这可能会为第一个操作数启用隐式类型转换。例如,如果:
x<=y
如果找不到与运算符 < =
匹配的定义,则可以将其重写为
(x<=>y)<=0
甚至
0(y <=>x)
通过这种重写可以看到,new 运算符 < = >
执行三向比较,得到一个可以与0进行比较的值:
· 如果 x < = > y
比较等于0,x 和 y 等于或等于。
· 如果 x < = > y
小于0,则 x 小于 y。
· 如果 x < = > y
的值比较大于0,则 x 大于 y。
运算符 < = > 的返回类型不是一个整数值。返回类型是一种表示比较类别的类型,可以是强序、弱序或纯序。这些类型支持与 0 进行比较以处理结果。
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 N 天,点击查看活动详情”