Sometimes I have structs such as this --
struct aggregate1 {
std::string name;
std::vector<ValueT> options;
size_t foobar;
// ...
};
-- where (in)equality is simply defined as (in)equality of all members: lhs_name == rhs_name && lhs_options == rhs_options && lhs_foobar == rhs_foobar
.
What's the "best" way to implement this? (Best as in: (Runtime-)Efficiency, Maintainability, Readability)
operator==
in terms of operator!=
operator!=
in terms of operator==
==
and !=
Note that this question is only about the (in)equality ops, as comparison (<
, <=
, ...) doesn't make too much sense for such aggregates.
The equality operators follow the same rules as the relational operators, but permit additional possibilities: a pointer can be compared to a constant integral expression with value 0, or to a pointer to void . If two pointers are both null pointers, they compare as equal.
Comparison operators are binary operators that test a condition and return 1 if that condition is logically true and 0 if that condition is false.
We compare the strings by using the strcmp() function, i.e., strcmp(str1,str2). This function will compare both the strings str1 and str2. If the function returns 0 value means that both the strings are same, otherwise the strings are not equal.
I would do this but maybe move operator== definition to cpp file. Leave operator!= to be inline
Remember to compare member variables that are most likely to differ first so the rest are short-circuited and performance is better.
struct aggregate1 {
bool operator==(const aggregate1& rhs) const
{
return (name == rhs.name)
&& (options == rhs.options)
&& (foobar == rhs.foobar);
}
bool operator!=(const aggregate1& rhs) const
{
return !operator==(rhs);
}
std::string name;
std::vector<ValueT> options;
size_t foobar;
// ...
};
Member or free function is a matter of taste, and writing separate implementations of ==
and !=
seems to me boring, error-prone (you may forget a member in just one of the two operators, and it will take time to notice) without adding anything in terms of efficiency (calling the other operator and applying !
has a negligible cost).
The decision is restricted to "is it better to implement operator==
in terms of operator!=
or the contrary?
In my opinion, in terms of maintainability/readability/efficiency it's the same; I'd only recommend to do it in the same way everywhere for the sake of consistency. The only case where you'd want to prefer to use one or the other as the "base operator" is when you know that, in the types contained in your structure, that operator is faster than its negation, but I don't know when this could happen.
In C++20, implementing equality and inequality operators can be as simple as declaring operator==
as default
:
struct S {
int x;
// ...
// As member function
bool operator==(S const &) const = default;
// As non-member function (hidden friend)
// friend bool operator==(S const &, S const &) = default;
};
If only operator==
is provided, a!=b
is interpreted as !(a==b)
according to overload resolution, so there is no need for providing an explicit overload for operator!=
.
I would argue that defaulting operator==
as a hidden friend is preferable because it works with reference-wrapped objects:
S s;
auto rs{std::ref(s)};
rs==rs; // OK for hidden friend; ill-formed if declared as member function
In this example, operator==
is not defined for std::reference_wrapper<S>
, but argument-dependent lookup (ADL) can select the hidden friend with operands implicitly-converted to S const &
. Notice, however, that ::operator==(rs,rs)
will only work if operator==
is defined as a free function because ADL is not triggered for qualified names.
IMHO, implement as friends and implement the operator==
(some STL algorithms will rely on this for example) and the operator!=
should be implemented as the negation of the equals operator.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With