比较以下结构的两个实例,我收到一个错误:
struct MyStruct1 {
Position(const MyStruct2 &_my_struct_2, const int _an_int = -1) :
my_struct_2(_my_struct_2),
an_int(_an_int)
{}
std::string toString() const;
MyStruct2 my_struct_2;
int an_int;
};
错误是:
错误C2678:二进制'==':找不到哪个运算符带有'myproj :: MyStruct1'类型的左手操作数(或者没有可接受的转换)
为什么?
在C ++中,struct
s没有默认生成的比较运算符。你需要自己写:
bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
return /* your comparison code goes here */
}
正如其他人所说,你需要自己实现一个比较功能。
有一种建议的方法要求编译器生成明显的/幼稚的(?)实现:请参阅here。
对C ++来说似乎有点无益,没有标准化,但结构/类通常有一些数据成员要从比较中排除(例如计数器,缓存结果,容器容量,上次操作成功/错误代码,游标),以及作为做出无数事情的决定,包括但不限于:
int
成员可以非常快速地消除99%的不等对象,而map<string,string>
成员可能经常具有相同的条目并且比较相对昂贵 - 如果值在运行时加载,程序员可能对编译器不可能有见解vector
,list
)时是否顺序是否重要,如果是这样,是否可以在比较之前就地对它们进行排序,而不是每次进行比较时使用额外的内存对临时数据进行排序union
的哪个成员进行比较operator==
的成员和基地(但可能有compare()
或operator<
或str()
或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==
为MyStruct2
。
这个实现和替代方案的含义将在下面讨论MyStruct1细节的标题下讨论。
利用std::tuple
的比较运算符来比较自己的类实例很容易 - 只需使用std::tie
以所需的比较顺序创建对字段的引用元组。从here推广我的例子:
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...
当你“拥有”(即可以编辑公司和第三方库的一个因素)你要比较的类时,尤其是C ++ 14准备从return
语句中推导出函数返回类型时,通常可以更好地添加一个“tie”成员函数到您希望能够比较的类:
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 operators(搜索less_than_comparable
)。如果由于某种原因它不合适,你可能会或可能不喜欢支持宏(online)的想法:
#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成员领带版here)
选择提供一个独立的成员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
的默认值来阻止an_int
s的这种隐式构造进行比较。)
会员实施
如果你想避免从MyStruct1
隐式构造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
s痛苦地被创造出来被扔掉!对于具有浮点值的类型,比较可见表示意味着显示的数字数决定了在比较期间几乎相等的值被视为相等的容差。
您需要为operator ==
明确定义MyStruct1
。
struct MyStruct1 {
bool operator == (const MyStruct1 &rhs) const
{ /* your logic for comparision between "*this" and "rhs" */ }
};
现在==比较对于2个这样的对象是合法的。
比较不适用于C或C ++中的结构。比较字段。
从C ++ 20开始,应该可以通过声明一个==
(“太空飞船”运算符)将一整套默认比较运算符(<=
,default three-way comparison operator等)添加到类中,如下所示:
struct Point {
int x;
int y;
auto operator<=>(const Point&) const = default;
};
使用兼容的C ++ 20编译器,将该行添加到MyStruct1和MyStruct2可能足以允许相等比较,假设MyStruct2的定义是兼容的。
默认情况下,结构没有==
运算符。你必须编写自己的实现:
bool MyStruct1::operator==(const MyStruct1 &other) const {
... // Compare the values, and return a bool result.
}
开箱即用,==运算符仅适用于基元。要使代码生效,需要重载结构的==运算符。
因为您没有为结构编写比较运算符。编译器不会为您生成它,因此如果您想要进行比较,则必须自己编写。