As other people have said, you need to implement the comparison function yourself.
There is a suggested way to ask the compiler to generate an obvious / naive (?) Implementation: see here .
C ++ may seem a little useless to not standardize this, but often structures / classes have some data elements that need to be excluded from comparison (for example, counters, cached results, container capacity, last successful operation code / error code, cursors), as well decisions on a variety of things, including but not limited to:
- which fields to compare first, for example, comparing a specific
int member can very quickly eliminate 99% of unequal objects, while the map<string,string> element can often have the same records and it is comparatively expensive to compare - if the values are loaded at run time, the programmer can understand that the compiler cannot - string comparison: case sensitivity, equivalence of spaces and delimiters, withdrawal from conventions ...
- precision when comparing floating point numbers
- whether NaN floating point values should be considered equal
- comparing pointers or pointers to data (and, if the latter, how to find out if pointers belong to arrays and how many objects / bytes need to be compared)
- Does the order matter when comparing unsorted containers (for example,
vector , list ) and, if so, is it possible to sort them in place before comparing or using additional memory to sort the temporary data each time the comparison is performed - how many elements of the array currently contain valid values that should be compared (is there a size or an hour somewhere?)
- which
union member to compare - normalization: for example, date types can allow a day-off or month-year off, or a rational / fractional object can have 6/8, and the other has 3/4, which, for performance reasons, they adjust lazily with a separate normalization step; You may need to decide whether to initiate normalization before comparing.
- what to do if weak pointers are invalid
- how to work with members and databases that themselves do not implement
operator== (but can have compare() or operator< or str() or getters ...) - what locks should be performed when reading / comparing data that other threads might want to update
Thus, it is nice to have a mistake until you clearly think about what the comparison should mean for your particular structure, instead of allowing it to compile, but not give a meaningful result at runtime .
All this suggests that it would be nice if C ++ allowed you to say bool operator==() const = default; when you decided that the "naive" test "member by member" == was in order. The same for != Given multiple members / databases, the implementation of "default" < , <= , > and >= seems hopeless, although cascading based on the declaration order is possible, but very unlikely to be required given the conflicting imperatives for ordering members ( the grounds are mandatory before the members, grouping by accessibility, construction / destruction before dependent use). To be more widely useful, C ++ will require a new annotation system for data / database elements that will guide the selection - it would be nice to have in the Standard, albeit ideally in combination with generating custom code based on AST ... I expect that it will happen one day.
Typical implementation of equality operators
Believable implementation
It is likely that a reasonable and effective 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; }
Please note that operator== also needed for MyStruct2 .
The implications of this implementation and its alternatives are discussed in the "Discussion of Your MyStruct1 Features" section below.
A consistent approach to ==, <,> <=, etc.
It's easy to use std::tuple comparison operators to compare your own class instances - just use std::tie to create tuples of field references in the desired comparison order. Summarizing my example from 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); }
When you “own” (that is, you can edit the factor with corporate and third-party libraries) the class you want to compare, and especially with the readiness of C ++ 14 to deduce the type of the return value of the function from the return , it is often better to add a “bind” member function to the class, which you want to compare:
auto tie() const { return std::tie(my_struct1, an_int); }
Then the above comparisons simplify to:
inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs) { return lhs.tie() == rhs.tie(); }
If you need a more complete set of comparison operators, I suggest increasing the operators (look for less_than_comparable ). If for some reason this does not fit, you may or may not like the idea of supporting macros (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)
... what can be used a la ...
#define MY_STRUCT_FIELDS(X) X.my_struct2, X.an_int TIED_COMPARISONS(MyStruct1, MY_STRUCT_FIELDS)
(C ++ 14-member version here )
Discussion of the specifics of your MyStruct1
There are consequences for choosing to provide a standalone operator==() member of operator==() ...
Standalone implementation
You need to make an interesting decision. Since your class can be implicitly created from MyStruct2 , a standalone / non bool operator==(const MyStruct2& lhs, const MyStruct2& rhs) member bool operator==(const MyStruct2& lhs, const MyStruct2& rhs) function will support ...
my_MyStruct2 == my_MyStruct1
... first creating a temporary MyStruct1 from my_myStruct2 , and then doing a comparison. This will definitely leave MyStruct1::an_int set to the default constructor parameter -1 . Depending on whether you an_int comparison in the implementation of your operator== , MyStruct1 may or may not compare it with MyStruct2 which itself is compared to MyStruct1 my_struct_2 ! In addition, creating a temporary MyStruct1 can be a very inefficient operation, as it involves copying the existing member my_struct2 to a temporary one, only to drop it after comparison. (Of course, you can prevent this implicit MyStruct1 construct for comparison by MyStruct1 making this constructor explicit or by removing the default value for an_int .)
Implementation of the participants
If you want to avoid implicitly constructing MyStruct1 from MyStruct2 , make the comparison operator a member function:
struct MyStruct1 { ... bool operator==(const MyStruct1& rhs) const { return tie() == rhs.tie();
Note that the const keyword - necessary only for member implementation - tells the compiler that the objects being compared do not change them, therefore they can be allowed for const objects.
Comparing Visible Views
Sometimes the easiest way to get the comparison you want may be ...
return lhs.to_string() == rhs.to_string();
... which is often very expensive - these string painfully created to be thrown away! For types with floating point values, comparing visible representations means that the number of digits displayed determines the tolerance within which almost equal values are considered equal during comparison.