使用比较运算符 < = >
运算符 < = > 应该返回一个比较类别类型之一的值,表示比较结果以及该结果是否能够创建强/总排序、弱排序或部分排序的信息。
例如,这就是为 MyType 类型定义独立运算符 < = > 的方法:
std::strong_ordering operator<=> (MyType x, MyOtherType y)
{
if (xlsEqualToY)
return std::strong_ordering::equal; if (xlsLessThanY)
return1 std::strong_ordering::less; return std::strong_ordering::greater;
}
或者作为一个更具体的例子,为 MyType 类型定义运算符 < = > :
class MyType {
..-
std::strong_ordering operator<=> (const MyType& rhs) const { return value == rhs.value ? std::strong_ordering::equal :
value <rhs.value ? std::strong_ordering::less :
std::strong_ordering::greater; }
};
但是,通过将运算符映射到基础类型的结果来定义运算符通常更容易。因此,上面的成员运算符 < = > 最好只生成其成员值的值和类别:
class MyType { ..-
auto operator<=> (const MyType& rhs) const { return value <=> rhs.value;
} };
这不仅返回正确的值,还确保返回值具有正确的比较类别类型,具体取决于成员值的类型。
调用操作符 < = >
你可以直接调用任何定义操作符< = >:
MyType x,y;
...
x<=>y
如前所述,运算符 < = > 是为所有基本类型预定义的,关系运算符是为这些基本类型定义的:
int x=17,y=42; x<=>y
//yields std::strong_ordering::less
x<=>17.0 //yields std::partial_ordering::equivalent
&x <=> &x //yields std::strong_ordering::equal
&x <=> nullptr //ERROR:relational comparison with nullptr not supported
此外,所有提供关系运算符的 C++标准程式库现在也提供运算符 < = > ,例如:
std::string{"hi"} <=> "hi" //yields std::strong_ordering::equal;
std::pair{42, 0.0} <=> std::pair{42,7.7} //yields std::partial_ordering::less
对于您自己的类型,您只需将运算符 < = > 定义为成员或独立函数。
请记住,返回类型取决于比较类别。您可以检查特定的返回值:
if (x <=> y == std::strong_ordering::equal) //might not compile
然而,与0进行比较总是可能的,而且通常更容易:
if (x <=> y ==0)
此外,由于关系运算子调用的新改写, < = > 可能会被间接调用:
if (!(x < y ll y < x)) //might call operator<=> to check for equality
或者:
if(x<=y&& y<=x) //might call operator<=>to check for equality
注意那个operator!= 永远不会被重写为调用操作符 < = > 。但是,它可能会调用由默认运算符 < = > 成员隐式生成的 operator<=>member 。
处理多个运算符
为了基于多个属性计算运算符 < = > 的结果,通常只需要实现一个子比较链,直到结果不相等/等价,或者到达要比较的最终属性
class Person {
.--
auto operator<=> (const Person& rhs) const
{ auto cmp1 = lastname <=> rhs.lastname; //primary member for ordering
if (cmp1 != 0) return cmp1 //return result
if not equal auto cmp2 = firstname <=> rhs.firstname; //secondary member for ordering
if (cmp2 != 0) return cmp2; //return result ifnot equal
return value <=> rhs.value; //final member for ordering }
};
但是,如果属性具有不同的比较类别,则不会编译返回类型。例如,如果一个成员名称是字符串,而一个成员值是 double,那么返回类型就会发生冲突:
class Person {
std::string name; double value;
··.
auto operator<=> (const Person& rhs) const { //ERROR: different return types deduiced
auto cmp1 = name <=> rhs.name;
if (cmp1 != 0) return cmp1; //return strong_ordering.for std::string
return value <=> rhs.value ; //return partial_ordering for double }
};
在这种情况下,您可以定义转换到最弱的比较类型。如果你知道最弱的比较类型,你可以直接用它作为返回类型:
class Person {
std::string name;
double value;
...
std::partial_ordering operator<=> (const Person& rhs) const { //OK
auto cmp1 =name <=> rhs.name;
if (cmp1 !=0) return cmp1; //strong_ordering converted to return type
return value <=> rhs.value; //partial_ordering used us the return type }
};
如果您不知道比较类型(例如,它们的类型是一个模板参数) ,您可以使用一个新的类型 trait std: : common _ ratio _ type < > 来计算最强的比较类别:
class Person { std::string name;
double value;
...
auto operator<=> (const Person& rhs) const
→>std::common_comparison_category_t<decltype(name <=> rhs.name),
decltype(value <=> rhs.value)> {
auto cmp1= name <=> rhs.name;
if (cmp1 !=0) return cmp1; //used as or converted to common comparison type
return value <=> rhs.value; // used as or converted to common comparison type }
};
通过使用尾随返回类型语法(前面是 auto,后面是 return type->) ,我们可以使用参数来计算比较类型。虽然在这种情况下可以只使用 name 而不是 rhs.name,但是这种方法通常是有效的(例如,也适用于独立函数)。
如果希望提供比内部使用的更强的类别,则必须将内部比较的所有可能值映射到返回类型的值。如果无法映射某些值,则可能包括一些错误处理。例如:
class Person{
std::string name; double value;
...
std::strong_ordering operator<=> (const Person& rhs) const {
auto cmp1=x.name <=>y.name;
if (cmp1 !=0) return cmp1; //return strong_ordering for std::string
auto cmp2 = x.value <=>y.value;//might be partial_ordering for double
//map partial_ordering to strong_ordering:
assert(cmp2 != std::partial_ordering::unordered); //RUNTIME ERROR ifunordered
return cmp2 == 0 ? std::strong_ordering::equal
:cmp2 > 0? std::strong_ordering::greater
:std::strong_ordering::less; }
};
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 N 天,点击查看活动详情”