C ++ 20引入了默认的比较,也就是“ spaceship”operator<=>
,它使您可以请求编译器生成的<
// <=
/ ==
/ !=
/ >=
/和/或>
具有明显/天真的(?)实现的运算符...
auto operator<=>(const MyClass&) const = default;
...但是您可以针对更复杂的情况(在下面讨论)进行自定义。有关语言建议,请参见此处,其中包含论据和讨论。这个答案仍然是相关的C ++ 17和更早的版本,以及洞察力的时候,你应该定制的实施operator<=>
....
对于C ++而言,如果没有早先对此进行标准化,可能会有所帮助,但是结构/类通常具有一些要从比较中排除的数据成员(例如,计数器,缓存的结果,容器容量,上次操作成功/错误代码,游标),例如以及决定作出关于万物,包括但不限于:
- 首先比较哪个字段,例如比较特定
int
成员可能会很快消除99%的不相等对象,而一个map<string,string>
成员可能经常具有相同的条目并且比较起来比较昂贵-如果在运行时加载值,程序员可能会发现编译器不可能
- 比较字符串时:区分大小写,空格和分隔符的等效性,转义约定...
- 比较浮点/双精度时的精度
- NaN浮点值是否应视为相等
- 比较指针或指向数据(如果是后者,则如何知道指针是否指向数组以及需要比较多少对象/字节)
- 是否为了事项比较无序的容器(如
vector
,list
),如果是是否这是确定比较与每一个比较完成的时间使用额外的内存来排序的临时前将其就地排序
- 当前有多少个数组元素持有应比较的有效值(某处是否有大小或前哨?)
union
比较哪个成员
- 归一化:例如,日期类型可能允许超出范围的某月某天或某年的某个月,或者有理/分数对象可能有6/8的精度,而另一个有3/4的精度,出于性能原因,它们可以纠正懒惰地进行单独的标准化步骤;您可能需要在比较之前决定是否触发标准化
- 弱指针无效时该怎么办
- 如何处理未实现
operator==
自身的成员和基础(但可能具有compare()
or operator<
或str()
or getters ...)
- 在读取/比较其他线程可能想要更新的数据时必须采取什么锁
因此,在您明确考虑比较对您的特定结构意味着什么之前,有一个错误会很好,而不是让它编译但在运行时没有给您有意义的结果。
综上所述,如果C ++让您说出bool operator==() const = default;
确定“幼稚的”逐成员==
测试是可以的,那将是一个好习惯。相同!=
。鉴于多个成员/基地,“默认” <
,<=
,>
,以及>=
实现似乎无望,但-级联的声明的可能,但不太可能是什么希望,因为冲突的紧迫任务成员排序(基地是必然成员之前,通过分组的秩序的基础上,无障碍使用,依赖使用前的构造/破坏)。为了更广泛地发挥作用,C ++将需要一个新的数据成员/基础注释系统来指导选择-尽管这在标准中将是一件很棒的事情,理想情况下,它还可以与基于AST的用户定义代码生成结合使用...我希望它'
等式运算符的典型实现
合理的实施
这是可能的,合理的和有效的实现将是:
inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
return lhs.my_struct2 == rhs.my_struct2 &&
lhs.an_int == rhs.an_int;
}
请注意,这也需要operator==
for MyStruct2
。
在下面的“ MyStruct1的详细信息的讨论”标题下讨论了此实现的含义和替代方法。
对==,<,> <=等的一致方法
利用std::tuple
的比较运算符比较您自己的类实例很容易-只需std::tie
按所需的比较顺序创建对字段的引用元组即可。从这里概括我的例子:
inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
return std::tie(lhs.my_struct2, lhs.an_int) ==
std::tie(rhs.my_struct2, rhs.an_int);
}
inline bool operator<(const MyStruct1& lhs, const MyStruct1& rhs)
{
return std::tie(lhs.my_struct2, lhs.an_int) <
std::tie(rhs.my_struct2, rhs.an_int);
}
// ...etc...
当您“拥有”(即可以使用Corporate和3rd party库编辑一个因子)要比较的类时,尤其是C ++ 14准备从return
语句中推断函数返回类型时,添加一个“将成员函数绑定到您想要比较的类:
auto tie() const { return std::tie(my_struct1, an_int); }
然后,以上比较简化为:
inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
return lhs.tie() == rhs.tie();
}
如果您需要比较完整的比较运算符集,我建议使用boost运算符(搜索less_than_comparable
)。如果由于某种原因不合适,您可能会或可能不会喜欢支持宏的概念(在线):
#define TIED_OP(STRUCT, OP, GET_FIELDS) \
inline bool operator OP(const STRUCT& lhs, const STRUCT& rhs) \
{ \
return std::tie(GET_FIELDS(lhs)) OP std::tie(GET_FIELDS(rhs)); \
}
#define TIED_COMPARISONS(STRUCT, GET_FIELDS) \
TIED_OP(STRUCT, ==, GET_FIELDS) \
TIED_OP(STRUCT, !=, GET_FIELDS) \
TIED_OP(STRUCT, <, GET_FIELDS) \
TIED_OP(STRUCT, <=, GET_FIELDS) \
TIED_OP(STRUCT, >=, GET_FIELDS) \
TIED_OP(STRUCT, >, GET_FIELDS)
...然后可以使用...
#define MY_STRUCT_FIELDS(X) X.my_struct2, X.an_int
TIED_COMPARISONS(MyStruct1, MY_STRUCT_FIELDS)
(C ++ 14成员关系版本在这里)
讨论MyStruct1的细节
选择提供独立会员还是独立会员有其含义operator==()
...
独立实施
您有一个有趣的决定。由于您的类可以由隐式构造MyStruct2
,因此独立/非成员bool operator==(const MyStruct2& lhs, const MyStruct2& rhs)
函数将支持...
my_MyStruct2 == my_MyStruct1
...首先创建一个临时MyStruct1
的my_myStruct2
,然后做比较。这肯定会保留MyStruct1::an_int
为构造函数的默认参数值-1
。取决于您是否在您an_int
的实现中包含比较operator==
,一个MyStruct1
可能等于或可能不等于MyStruct2
本身本身等于MyStruct1
的my_struct_2
成员!此外,创建临时项MyStruct1
可能是非常低效的操作,因为它涉及将现有my_struct2
成员复制到临时项,而只是在比较之后将其丢弃。(当然,您可以MyStruct1
通过构造explicit
或删除的默认值来防止s的这种隐式构造以进行比较an_int
)。
会员实施
如果要避免MyStruct1
从隐式构造a MyStruct2
,则将比较运算符设为成员函数:
struct MyStruct1
{
...
bool operator==(const MyStruct1& rhs) const
{
return tie() == rhs.tie(); // or another approach as above
}
};
请注意,const
关键字(仅对于成员实现而言是必需的)建议编译器比较对象不会对其进行修改,因此可以在const
对象上使用。
比较可见的表示
有时,获得所需比较的最简单方法是...
return lhs.to_string() == rhs.to_string();
...这通常也很昂贵-那些string
痛苦地创造出来的东西被扔掉了!对于具有浮点值的类型,比较可见表示表示显示位数的数量确定了比较期间将近似等于的值视为相等的容差。
struct
s的相等性?而且,如果您想要简单的方法,memcmp
那么您的结构总是不包含指针那么长时间。