How to avoid mistakes in operator== implementations in C++?
I often have classes which provide simple member-by-member comparison:
class ApplicationSettings
{
public:
bool operator==(const ApplicationSettings& other) const;
bool operator!=(const ApplicationSettings& other) const;
private:
SkinType m_ApplicationSkin;
UpdateCheckInterval m_IntervalForUpdateChecks;
bool m_bDockSelectionWidget;
// Add future members to operator==
};
bool ApplicationSettings::operator==(const ApplicationSettings& other) const
{
if (m_ApplicationSkin != other.m_ApplicationSkin)
{
return false;
}
if (m_IntervalForUpdateChecks != other.m_IntervalForUpdateChecks)
{
return false;
}
if (m_bDockSelectionWidget != other.m_bDockSelectionWidget)
{
return false;
}
return true;
}
bool ApplicationSettings::operator!=(const ApplicationSettings& other) const;
{
return ( ! operator==(other));
}
Given that C++ at this time does not provide any construct to generate an operator==, is there a better way to ensure future members become part of the comparison, other than the comment I added below the data members?
It doesn't catch every case, and annoyingly it's compiler and platform dependent, but one way is to static_assert
based on the sizeof
of the type:
static_assert<sizeof(*this) == <n>, "More members added?");
where <n>
is a constexpr
.
If new members are introduced then, more often than not, sizeof
changes, and you'll induce a compile time failure.
Focusing solely on the technical aspect of this, you can leverage the fact the standard library std::tuple
type overloads operator==
for member-wise comparison. If you don't mind sacrificing simple member access elsewhere, you can just wrap your members in a tuple. Something like this:
#include <tuple>
class ApplicationSettings
{
public:
bool operator==(const ApplicationSettings& other) const;
bool operator!=(const ApplicationSettings& other) const;
private:
enum m {
ApplicationSkin,
IntervalForUpdateChecks,
bDockSelectionWidget
};
std::tuple<
SkinType,
UpdateCheckInterval,
bool
> m_Data;
};
Now implementing the comparison operator is a no-brainer:
bool ApplicationSettings::operator==(const ApplicationSettings& other) const {
m_Data == other.m_Data;
}
Of course, the sacrifice is that other member functions need to access other members via std::get<m::ApplicationSkin>(m_Data)
. Which could raise a fair few eyebrows.
上一篇: 两个对象在同一个类下的比较