Idea:
In C++, often a straightforward implementation of comparison operators is needed. In C++11, they can be conveniently implemented using std::tie
. The following mixin class automatically enables comparison operators by deriving a class T
from Comparable<T>
.
Implementation: (please review this part, requires C++14)
// A mixin class that makes derived classes comparable
template<typename T>
struct Comparable {
// nothing is needed here
};
// Default: Assume the client class offers a tie method
// Alternative: The client class can override this method
template<typename T>
auto tie(const Comparable<T>& a_object)
{
return static_cast<const T&>(a_object).tie();
}
template<typename T>
bool operator==(const Comparable<T>& a_lhs, const Comparable<T>& a_rhs)
{
return tie(a_lhs) == tie(a_rhs);
}
template<typename T>
bool operator!=(const Comparable<T>& a_lhs, const Comparable<T>& a_rhs)
{
return tie(a_lhs) != tie(a_rhs);
}
template<typename T>
bool operator<(const Comparable<T>& a_lhs, const Comparable<T>& a_rhs)
{
return tie(a_lhs) < tie(a_rhs);
}
template<typename T>
bool operator>(const Comparable<T>& a_lhs, const Comparable<T>& a_rhs)
{
return tie(a_lhs) > tie(a_rhs);
}
template<typename T>
bool operator<=(const Comparable<T>& a_lhs, const Comparable<T>& a_rhs)
{
return tie(a_lhs) <= tie(a_rhs);
}
template<typename T>
bool operator>=(const Comparable<T>& a_lhs, const Comparable<T>& a_rhs)
{
return tie(a_lhs) >= tie(a_rhs);
}
Usage Example: Client code then could look like the following. The implementation of the tie function automatically defines a lexicographical ordering for all supported operations.
struct Client : public Comparable<Client> { auto tie() const { return std::tie(m_a, m_b); } int m_a = 1; int m_b = 2; }; Client a, b; b.m_b = 5; const bool isEqual = (a == b); const bool isNotEqual = (a != b); const bool isSmaller = (a < b); const bool isGreater = (a > b); const bool isSmallerOrEqual = (a <= b); const bool isGreaterOrEqual = (a >= b);
Advantage: There is no need anymore to implement many comparison operators by hand for many classes individually. If there are many different classes requiring comparison operators with straightforward semantics this can save quite some code.