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.

链接地址: http://www.djcxy.com/p/73772.html

上一篇: 两个对象在同一个类下的比较

下一篇: 如何避免C ++中operator ==实现中的错误?