Consider the following set of classes and the relationship of their operators: We can implement them in two distinct ways. The first where the operators are defined within the class, and the latter where they are defined outside of the class...
template<typename T>
struct A {
T value;
T& operator+(const A<T>& other) { return value + other.value; }
// other operators
};
temlate<typename T>
struct B {
T value;
T& operator+(const B<T>& other) { return value + other.value; }
};
// Or...
template<typename T>
struct A {
T value;
};
template<typename T>
T& operator+(const A<T>& lhs, const A<T>& rhs) { return lhs.value + rhs.value; }
// ... other operators
template<typename T>
struct B {
T value;
};
template<typename T>
T& operator+(const B<T>& lhs, const B<T>& rhs) { return lhs.value + rhs.value; }
// ... other operators
Is there any way in C++ where I would be able to make a single class or struct of operators to where I could simply be able to declare or define them within any arbitrary class C without having to write those same operators multiple times for each class? I'm assuming that the operators will have the same behavior and property for each distinct class that defines them considering that they will all follow the same pattern.
For example:
template<typename T, class Obj>
struct my_operators {
// define them here
};
// Then
template<typename T>
struct A {
T value;
my_operators ops;
};
template<typename T>
struct B {
T value;
my_operators ops;
};
Remember I'm restricting this to C++17 as I'm not able to use any C++20 features such as Concepts... If this is possible, what kind of method or construct would I be able to use, what would its structure and proper syntax look like? If this is possible then I'd be able to write the operators once and just reuse them as long as the pattern of the using classes matches without having to write those operators for each and every individual class...
What about using CRTP inheritance?
#include <iostream>
template <typename T>
struct base_op
{
auto operator+ (T const & o) const
{ return static_cast<T&>(*this).value + o.value; }
};
template<typename T>
struct A : public base_op<A<T>>
{ T value; };
template<typename T>
struct B : public base_op<B<T>>
{ T value; };
int main()
{
A<int> a1, a2;
B<long> b1, b2;
a1.value = 1;
a2.value = 2;
std::cout << a1+a2 << std::endl;
b1.value = 3l;
b2.value = 5l;
std::cout << b1+b2 << std::endl;
}
Obviously this works only for template classes with a value
member.
For the "outside the class" version, base_op
become
template <typename T>
struct base_op
{
friend auto operator+ (T const & t1, T const & t2)
{ return t1.value + t2.value; }
};
-- EDIT --
The OP asks
now I'm struggling to write their equivalent
+=
,-=
,*=
,/=
operators within this same context... Any suggestions?
It's a little more complicated because they must return a reference to the derived object... I suppose that (for example) operator+=()
, inside base_op
, could be something as
T & operator+= (T const & o)
{
static_cast<T&>(*this).value += o.value;
return static_cast<T&>(*this);
}