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...
CodePudding user response:
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
CodePudding user response:
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.
CodePudding user response:
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.