Should "operator !=" always be implemented via "operator ==" in C++?
I currently review an old C++ codebase and see a lot of code going like this:
bool SomeClass::operator==( const SomeClass& ot开发者_开发百科her ) const
{
return member1 == other.member1 && member2 == other.member2;
}
bool SomeClass::operator!=( const SomeClass& other ) const
{
return member1 != other.member1 || member2 != other.member2;
}
clearly comparison logic is duplicated and the code above will likely have to be changed in two places instead of in one.
AFAIK the typical way to implement operator!=
is like this:
bool SomeClass::operator!=( const SomeClass& other ) const
{
return !( *this == other );
}
In the latter case whatever logic change occurs in operator==
it will automatically reflected in operator!=
since it just calls operator==
and performs negation.
Is there any resonable case where operator!=
should be implemented in any other way except just reusing operator==
in C++ code?
In most cases the semantics of a!=b
should be equal to !(a==b)
.
The same is true for about all the other operators: a<b
should be equal to !(a=>b)
and to !(a==b || a>b)
and to a<=b && !(a==b)
and so on and so forth.
To this purpose boost.operators offers some awesome tools to automatically generate operators in function of the others.
However when you give some particular semantics to your operators (ie: you don't use ==
to check whether two items are the same, but to do some fancy stuff like STL does with >>
and <<
) you could want to give them different implementations.
This practice, in general, is not suggested, although even STL and many boost libraries do that.
EDIT - A little addition:
what I said so far concerns only the semantics of operators. If you decide that the semantics of your a!=b
should be !(a==b)
you've got two ways to implement it:
by calling the other operator, which is what happens if you use boost.operators:
bool operator!=(a,b) { return !(a==b); }
implementing both of them from scratch.
The first method is usually easier to implement and safer. The most common thing which could justify the second option are optimizations, although it's probably not worth it: modern compilers won't add any overhead in most cases (if you look to boost.operators source code you'll see many comments about how they rely on NRVO to add no overhead, or how their code change if compiler doesn't provide NRVO).
Whatever option you choose, anyway, it should make no difference to your application logic, since what matters is the semantics (ie: how your operators behaves, what they return for any possible input).
IMHO it's both reasonable and robust to implement != in terms of ==. (or the other way around)
semantically yes (meaning that == should be the logical complement of !=), but practically (coding) you do not have to.
Is there any resonable case where
operator!=
should be implemented in any other way except just reusingoperator==
in C++ code?
I don’t think so. But the same holds for other code as well, e.g. postfix ++
should always be implemented in terms of prefix ++
(except of course for native types where the optimizer can generate more efficient code, but I believe even then the argument holds) and operator +
should almost always be implemented in terms of operator +=
(the exception is when you’re working with proxy objects to delay execution).
This is why std::relops
exists.
精彩评论