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.
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.