After I overloaded <
, ==
, +
, -
, *
... in a class named Fraction
:
class Fraction:
public:
// constructor, operator= ... defined before
bool operator<(const Fraction& A) const;
bool operator==(const Fraction& A) const;
Fraction operator+(const Fraction& A) const;
Fraction operator-(const Fraction& A) const;
Fraction operator*(const Fraction& A) const;
Fraction operator/(const Fraction& A) const;
I could use these above 'basic' operators to overload >
, +=
, ++
and +
from left...
class Fraction:
public:
bool operator>(const Fraction& A) const {
return A < *this;
}
bool operator!=(const Fraction& A) const {
return !(*this == A);
}
Fraction &operator+=(const Fraction& A) const {
return *this = *this + A;
}
Fraction operator++() const {
return *this += 1;
}
friend Fraction &operator+(const int& a, const Fraction& A) const {
return A + a;
}
However, I also have classes like RealNumber
, Complex
... They also need overloading, but only overloading <
, ==
, +
, -
, *
... differs, while overloading >
, +=
, ++
... is similar. (just a typename difference)
So I'm curious about an elegant way to reduce the similar part, I've learnt the CRTP that possible helps, but it only overloads comparison...
Use a CRTP base class like boost::operators
to define the boring bits. You just define the methods below, and it automatically adds all the other operators for you.
class Fraction {
: boost::operators<Fraction>
public:
bool operator<(const Fraction& x) const {...}
bool operator==(const Fraction& x) const {...}
Fraction& operator+=(const Fraction& x) {...}
Fraction& operator-=(const Fraction& x) {...}
Fraction& operator*=(const Fraction& x) {...}
Fraction& operator/=(const Fraction& x) {...}
Fraction& operator%=(const Fraction& x) {...}
Fraction& operator|=(const Fraction& x) {...}
Fraction& operator&=(const Fraction& x) {...}
Fraction& operator^=(const Fraction& x) {...}
Fraction& operator++() {...}
Fraction& operator--() {...}
}
https://www.boost.org/doc/libs/1_41_0/libs/utility/operators.htm
You may be interested in the three-way comparison operator (Also known as the space ship operator):
It does however require C++20
It won't reduce all the operators you will have to write. But at least the comparison operators you have to write are reduced.
If we are talking about C++20, then
/* some type traits */
namespace detail {
template <typename T> struct is_number_helper : public std::false_type {};
template <> struct is_number_helper<Fraction> : public std::true_type {};
/* do for every number class */
}
template <typename T>
inline constexpr bool is_number = detail::is_number_helper<std::remove_cv_t<T>>::value;
/* concept */
template <typename T>
concept Number = is_number<T>;
/* generic operator (for all Number types) */
template <Number N>
constexpr N operator + (const N& lhs, const N& rhs) { /*...*/ }
/* ... */
/* specialized operator */
constexpr Complex operator + (const Complex& lhs, const Complex& rhs) { /*...*/ }
/* ... */
If you don't specialize an operator, the generic one will be used, if there is a specialized operator, then that.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.