比较 C++ 中的结构时找不到 == 运算符

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5740310/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 18:47:20  来源:igfitidea点击:

No == operator found while comparing structs in C++

c++structcomparison-operators

提问by Jonathan

Comparing two instances of the following struct, I receive an error:

比较以下结构的两个实例,我收到一个错误:

struct MyStruct1 {
    MyStruct1(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;
};

The error is:

错误是:

error C2678: binary '==' : no operator found which takes a left-hand operand of type 'myproj::MyStruct1' (or there is no acceptable conversion)

错误 C2678:二进制“==”:未找到采用“myproj::MyStruct1”类型的左侧操作数的运算符(或没有可接受的转换)

Why?

为什么?

回答by Anthony Williams

In C++, structs do not have a comparison operator generated by default. You need to write your own:

在 C++ 中,structs 没有默认生成的比较运算符。你需要自己写:

bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
    return /* your comparison code goes here */
}

回答by Tony Delroy

C++20 introduced default comparisons, aka the "spaceship" operator<=>, which allows you to request compiler-generated </<=/==/!=/>=/ and/or >operators with the obvious/naive(?) implementation...

C++20 引入了默认比较,也就是 "spaceship"operator<=>,它允许您请求编译器生成的</ <=/ ==/ !=/ >=/ 和/或>具有明显/naive(?) 实现的运算符...

auto operator<=>(const MyClass&) const = default;

...but you can customise that for more complicated situations (discussed below). See herefor the language proposal, which contains justifications and discussion. This answer remains relevant for C++17 and earlier, and for insight in to when you should customise the implementation of operator<=>....

...但您可以针对更复杂的情况进行自定义(如下所述)。请参阅此处的语言提案,其中包含理由和讨论。这个答案仍然是相关的C ++ 17和更早的版本,以及洞察力的时候,你应该定制的实施operator<=>....

It may seem a bit unhelpful of C++ not to have already Standardised this earlier, but often structs/classes have some data members to excludefrom comparison (e.g. counters, cached results, container capacity, last operation success/error code, cursors), as well as decisions to makeabout myriad things including but not limited to:

C++ 不早点标准化这似乎有点无用,但通常结构/类有一些数据成员要从比较中排除(例如计数器、缓存结果、容器容量、上次操作成功/错误代码、游标),如以及对无数事情做出的决定,包括但不限于:

  • which fields to compare first, e.g. comparing a particular intmember might eliminate 99% of unequal objects very quickly, while a map<string,string>member might often have identical entries and be relatively expensive to compare - if the values are loaded at runtime, the programmer may have insights the compiler can't possibly
  • in comparing strings: case sensitivity, equivalence of whitespace and separators, escaping conventions...
  • precision when comparing floats/doubles
  • whether NaN floating point values should be considered equal
  • comparing pointers or pointed-to-data (and if the latter, how to know how whether the pointers are to arrays and of how many objects/bytes needing comparison)
  • whether order matters when comparing unsorted containers (e.g. vector, list), and if so whether it's ok to sort them in-place before comparing vs. using extra memory to sort temporaries each time a comparison is done
  • how many array elements currently hold valid values that should be compared (is there a size somewhere or a sentinel?)
  • which member of a unionto compare
  • normalisation: for example, date types may allow out-of-range day-of-month or month-of-year, or a rational/fraction object may have 6/8ths while another has 3/4ers, which for performance reasons they correct lazily with a separate normalisation step; you may have to decide whether to trigger a normalisation before comparison
  • what to do when weak pointers aren't valid
  • how to handle members and bases that don't implement operator==themselves (but might have compare()or operator<or str()or getters...)
  • what locks must be taken while reading/comparing data that other threads may want to update
  • 首先比较哪些字段,例如比较特定int成员可能会很快消除 99% 的不相等对象,而map<string,string>成员可能通常具有相同的条目并且比较起来相对昂贵 - 如果在运行时加载值,程序员可能会了解编译器不可能
  • 在比较字符串时:区分大小写、空格和分隔符的等效性、转义约定......
  • 比较浮点数/双精度数时的精度
  • NaN 浮点值是否应视为相等
  • 比较指针或指向数据(如果是后者,如何知道指针是否指向数组以及需要比较的对象/字节数)
  • 比较未排序的容器(例如vector, list)时顺序是否重要,如果是,是否可以在比较之前就地对它们进行排序与​​每次比较完成时使用额外的内存对临时对象进行排序
  • 有多少数组元素当前持有应该比较的有效值(某处是否有大小或哨兵?)
  • union要比较a 的哪个成员
  • 规范化:例如,日期类型可能允许超出范围的日期或月份,或者一个有理数/分数对象可能有 6/8ths 而另一个有 3/4ers,出于性能原因他们更正懒惰地使用单独的标准化步骤;您可能必须在比较之前决定是否触发规范化
  • 当弱指针无效时该怎么办
  • 如何处理没有实现operator==自己的成员和基础(但可能有compare()operator<str()或吸气剂......)
  • 在读取/比较其他线程可能想要更新的数据时必须采取哪些锁定

So, it's kind of nice to have an erroruntil you've explicitly thought about what comparison should mean for your specific structure, rather than letting it compile but not give you a meaningful result at run-time.

因此,在您明确考虑比较对您的特定结构意味着什么之前出现错误是一种很好的方式而不是让它编译但在运行时不给您有意义的结果

All that said, it'd be good if C++ let you say bool operator==() const = default;when you'd decided a "naive" member-by-member ==test wasok. Same for !=. Given multiple members/bases, "default" <, <=, >, and >=implementations seem hopeless though - cascading on the basis of order of declaration's possible but very unlikely to be what's wanted, given conflicting imperatives for member ordering (bases being necessarily before members, grouping by accessibility, construction/destruction before dependent use). To be more widely useful, C++ would need a new data member/base annotation system to guide choices - that would be a great thing to have in the Standard though, ideally coupled with AST-based user-defined code generation... I expect it'll happen one day.

所有这一切说,这将会是很好的如果C ++让你说bool operator==() const = default;,当你决定了“天真”成员,由成员==测试好的。对于!=. 给定多个成员/基,“默认” <<=>>=实现似乎无望 - 根据声明的顺序级联可能但不太可能是想要的,考虑到成员排序的冲突命令(基必须在成员之前,按可访问性、依赖使用前的构建/破坏)。为了更广泛地有用,C++ 需要一个新的数据成员/基注释系统来指导选择——尽管这在标准中是一件很棒的事情,理想情况下与基于 AST 的用户定义代码生成相结合......我期望它'

Typical implementation of equality operators

等式运算符的典型实现

A plausible implementation

一个合理的实现

It's likelythat a reasonable and efficient implementation would be:

这是可能的,合理的和有效的实现将是:

inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
    return lhs.my_struct2 == rhs.my_struct2 &&
           lhs.an_int     == rhs.an_int;
}

Note that this needs an operator==for MyStruct2too.

请注意,这也需要一个operator==for MyStruct2

Implications of this implementation, and alternatives, are discussed under the heading Discussion of specifics of your MyStruct1below.

此实现和替代方案的含义在下面的 MyStruct1 的细节讨论标题下进行了讨论

A consistent approach to ==, <, > <= etc

==、<、> <= 等的一致方法

It's easy to leverage std::tuple's comparison operators to compare your own class instances - just use std::tieto create tuples of references to fields in the desired order of comparison. Generalising my example from here:

很容易利用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...

When you "own" (i.e. can edit, a factor with corporate and 3rd party libs) the class you want to compare, and especially with C++14's preparedness to deduce function return type from the returnstatement, it's often nicer to add a "tie" member function to the class you want to be able to compare:

当您“拥有”(即可以编辑,具有公司和 3rd 方库的因素)要比较的类时,尤其是 C++14 准备从return语句中推断函数返回类型时,添加“ tie" 成员函数与您希望能够比较的类:

auto tie() const { return std::tie(my_struct1, an_int); }

Then the comparisons above simplify to:

那么上面的比较简化为:

inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
    return lhs.tie() == rhs.tie();
}

If you want a fuller set of comparison operators, I suggest boost operators(search for less_than_comparable). If it's unsuitable for some reason, you may or may not like the idea of support macros (online):

如果您想要一组更完整的比较运算符,我建议使用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)

...that can then be used a la...

...然后可以使用...

#define MY_STRUCT_FIELDS(X) X.my_struct2, X.an_int
TIED_COMPARISONS(MyStruct1, MY_STRUCT_FIELDS)

(C++14 member-tie version here)

此处为C++14 成员绑定版本)

Discussion of specifics of your MyStruct1

讨论 MyStruct1 的细节

There are implications to the choice to provide a free-standing versus member operator==()...

选择提供独立的与成员的operator==()...

Freestanding implementation

独立实施

You have an interesting decision to make. As your class can be implicitly constructed from a MyStruct2, a free-standing / non-member bool operator==(const MyStruct2& lhs, const MyStruct2& rhs)function would support...

你要做出一个有趣的决定。由于您的类可以从 a 隐式构造MyStruct2,因此独立/非成员bool operator==(const MyStruct2& lhs, const MyStruct2& rhs)函数将支持...

my_MyStruct2 == my_MyStruct1

...by first creating a temporary MyStruct1from my_myStruct2, then doing the comparison. This would definitely leave MyStruct1::an_intset to the constructor's default parameter value of -1. Depending on whether you include an_intcomparison in the implementation of your operator==, a MyStruct1might or might not compare equal to a MyStruct2that itself compares equal to the MyStruct1's my_struct_2member! Further, creating a temporary MyStruct1can be a very inefficient operation, as it involves copying the existing my_struct2member to a temporary, only to throw it away after the comparison. (Of course, you could prevent this implicit construction of MyStruct1s for comparison by making that constructor explicitor removing the default value for an_int.)

...首先创建一个临时MyStruct1from my_myStruct2,然后进行比较。这肯定会保留MyStruct1::an_int设置为构造函数的默认参数值-1。取决于您是否在您an_int的 实现中包含比较operator==, aMyStruct1可能会或可能不会与 a 比较,而 aMyStruct2本身比较等于MyStruct1my_struct_2成员!此外,创建一个临时对象MyStruct1可能是一个非常低效的操作,因为它涉及将现有my_struct2成员复制到一个临时对象,只是在比较后将其丢弃。(当然,您可以MyStruct1通过创建该构造函数explicit或删除s的默认值来防止s 的这种隐式构造以进行比较an_int。)

Member implementation

成员实现

If you want to avoid implicit construction of a MyStruct1from a MyStruct2, make the comparison operator a member function:

如果要避免MyStruct1从 a隐式构造a MyStruct2,请将比较运算符设为成员函数:

struct MyStruct1
{
    ...
    bool operator==(const MyStruct1& rhs) const
    {
        return tie() == rhs.tie(); // or another approach as above
    }
};

Note the constkeyword - only needed for the member implementation - advises the compiler that comparing objects doesn't modify them, so can be allowed on constobjects.

请注意const关键字 - 仅成员实现需要 - 建议编译器比较对象不会修改它们,因此可以在const对象上允许。

Comparing the visible representations

比较可见的表示

Sometimes the easiest way to get the kind of comparison you want can be...

有时,获得您想要的那种比较的最简单方法可能是……

    return lhs.to_string() == rhs.to_string();

...which is often very expensive too - those strings painfully created just to be thrown away! For types with floating point values, comparing visible representations means the number of displayed digits determines the tolerance within which nearly-equal values are treated as equal during comparison.

...这通常也非常昂贵 - 那些string痛苦地创造出来只是为了扔掉!对于具有浮点值的类型,比较可见表示意味着显示的位数决定了在比较期间将几乎相等的值视为相等的容差。

回答by iammilind

You need to explicitly define operator ==for MyStruct1.

您需要明确定义operator ==for MyStruct1

struct MyStruct1 {
  bool operator == (const MyStruct1 &rhs) const
  { /* your logic for comparision between "*this" and "rhs" */ }
};

Now the == comparison is legal for 2 such objects.

现在 == 比较对于 2 个这样的对象是合法的。

回答by Joe Lee

Starting in C++20, it should be possible to add a full set of default comparison operators (==, <=, etc.) to a class by declaring a default three-way comparison operator("spaceship" operator), like this:

在C ++ 20日起,它应该是可能的全套默认比较操作(添加==<=通过声明等)一类的默认三路比较操作符(“宇宙飞船”运营商),就像这样:

struct Point {
    int x;
    int y;
    auto operator<=>(const Point&) const = default;
};

With a compliant C++20 compiler, adding that line to MyStruct1 and MyStruct2 may be enough to allow equality comparisons, assuming the definition of MyStruct2 is compatible.

使用兼容的 C++20 编译器,假设 MyStruct2 的定义兼容,将该行添加到 MyStruct1 和 MyStruct2 可能足以允许相等比较。

回答by Rafe Kettler

Comparison doesn't work on structs in C or C++. Compare by fields instead.

比较不适用于 C 或 C++ 中的结构。改为按字段进行比较。

回答by Jonathan

By default structs do not have a ==operator. You'll have to write your own implementation:

默认情况下,结构没有==运算符。您必须编写自己的实现:

bool MyStruct1::operator==(const MyStruct1 &other) const {
    ...  // Compare the values, and return a bool result.
  }

回答by Babak Naffas

Out of the box, the == operator only works for primitives. To get your code to work, you need to overload the == operator for your struct.

开箱即用的 == 运算符仅适用于原语。为了让您的代码工作,您需要为您的结构重载 == 运算符。

回答by Babak Naffas

Because you did not write a comparison operator for your struct. The compiler does not generate it for you, so if you want comparison, you have to write it yourself.

因为您没有为结构编写比较运算符。编译器不会为你生成,所以如果你要比较,你必须自己写。