Reputation: 60421
I'm currently implementing some CRTP with a base class template<class CRTP> Base
and derived classes Derived1 : public Base<Derived1>
, Derived2 : public Base<Derived2>
...
The mathematical operators are defined in Base
and are of the type CRTP Base<CRTP>::operator+(const CRTP& rhs)
that means that we can add a Derived1
to a Derived1
but not a Derived2
to a Derived1
.
Furthermore, I have defined the operator Base<CRTP>& Base<CRTP>::operator()()
which means that Derived1()
will return Base<Derived1>&
.
I wonder if there is a solution to do the following :
Derived1 = Derived1 + Derived1 : OK
Derived2 = Derived2 + Derived2 : OK
Derived1 = Derived1 + Derived2 : NOT OK
Derived1 = Derived1() + Derived2() : OK
According to the last two lines :
The only thing I need to do this is to define an operator like that :
template<class CRTP0, class = typename std::enable_if</* SOMETHING */>::type>
Base<CRTP> Base<CRTP>::operator+(const Base<CRTP0>& rhs)
In the enable_if I would like something that is :
true
: if rhs is of the Base
typefalse
: if rhs is a Derived
typeDoes a such thing exist ? Do you have an other solution in mind ?
Thank you very much !
Upvotes: 1
Views: 1753
Reputation: 523494
The /* SOMETHING */ can be easily archived using
std::is_same
for the 'false' part of Derived andThe helper class is to determine whether a class is exactly a Base<?>
:
template <typename> struct IsBase : std::false_type {};
...
template <typename X> struct IsBase<Base<X>> : std::true_type {};
and then we could fill in that /* SOMETHING */ with:
std::is_same<Other, Self>::value || IsBase<Other>::value
Note that this allows Derived1 + Derived2()
.
Example: http://ideone.com/OGt0Q
#include <type_traits>
template <typename> struct IsBase : std::false_type {};
template <typename Self>
struct Base {
Base& operator()() {
return *this;
};
template <typename Other,
typename = typename std::enable_if<std::is_same<Other, Self>::value
|| IsBase<Other>::value>::type>
Self operator+(const Other& other) const {
return static_cast<const Self&>(*this);
}
};
template <typename X> struct IsBase<Base<X>> : std::true_type {};
struct D1 : Base<D1> {};
struct D2 : Base<D2> {};
int main() {
D1 d1;
D2 d2;
d1 + d1; // ok
d2 + d2; // ok
d1() + d2(); // ok
d1 + d2; // error
}
Upvotes: 2