Inheriting from a template class set of operators using CRTP

家住魔仙堡 提交于 2021-02-11 12:39:12

问题


This is a follow-up from this Q/A.

I'm in the process of taking user Jarod42's advice by using template <template<typename> class C, typename T> instead of the example that I have shown as my answer to the question.

My code currently looks like this:

template<template<typename> class C, typename T>
struct single_member_ops {
    friend auto operator+(const C<T>& lhs, const C<T>& rhs) 
    { return lhs.value + rhs.value; }
    friend auto operator+(const C<T>& lhs, const T& rhs)
    { return lhs.value + rhs;}
    friend auto operator+(const T& lhs, const C<T>& rhs)
    { return lhs + rhs.value;}

    friend auto operator+=(const C<T> & lhs, const C<T> & rhs) {
        C<T> temp;
        temp.value = lhs.value + rhs.value;
        return temp.value;
    }

    friend auto operator+=(const C<T>& lhs, const T& rhs ) {
        C<T> temp;
        temp.value = lhs.value + rhs;
        return temp.value;
    }

    friend auto operator+=(const T& lhs, const C<T>& rhs) {
        C<T> temp;
        temp.value = lhs + rhs.value;
        return temp.value;
    }

};

template<typename T>
struct A : public single_member_ops<A<T>, T>{
    T value;    
    A() = default;
    explicit A(T in) : value{in} {}
    explicit A(A<T>& in) : value{in.value} {}
    auto& operator=(const A<T>& rhs) { return value = rhs; }
    auto& operator=(const T& rhs) { return value = rhs; }
};

template<typename T>
struct B : public single_member_ops<B<T>, T> {
    T value;
    B() = default;
    explicit B(T in) : value{in} {}
    explicit B(B<T>& in) : value{in.value} {}
    auto& operator=(const B<T>& rhs) {return value = rhs;}
    auto& operator=(const T& rhs) { return value = rhs; }
};

int main() {
    A<int> a1(4);
    A<int> a2;
    A<int> a3{0};
    a2 = 6;
    a3 = a1 + a2; 

    B<int> b1(5);
    B<int> b2(7); 

    B<double> bd1(3.4);
    B<double> bd2(4.5); 

    auto x1 = a1 + a2;
    auto x2 = a1 + b2;
    auto x3 = b1 + bd1;
    //auto y1 = a2 - b2;
    //auto y2 = b2 - a1;

    A<int> z;
    z += a2 + a3;

    return z.value;
}

You can see it on Compiler Explorer

I'm only showing the +() and +=() operators to reduce the amount of code shown. I would prefer for all of my operators to be defined in this base class single_member_ops and to be a friend to all classes that will derive from this base class.

My code example above is generating compiler errors for the lines that the pertaining operator is not defined for the defined binary operator(s):

auto x2 = a1 + b2;
auto x3 = b1 + bd1;

It appears that I'm able to use the +() and +=() operators just fine for all types that match in both class and its type such as in A<int> and A<int> which is fine. However, let's say that I want to use them interchangeably such as in the following pseudo situations:

A<int> op A<double> 
A<int> op B<int>
A<int> op B<double>

What would I have to do, or what would my operators look like to achieve this? What else am I missing here?

来源:https://stackoverflow.com/questions/65993024/inheriting-from-a-template-class-set-of-operators-using-crtp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!