Reputation: 41220
I'm trying to build a templated base class that allows for assignment to any of its template types, like so:
#include <type_traits>
#include <utility>
template<typename T1, typename... Types>
class Base
{
public:
//assignment to base or derived class
template<typename T, typename std::enable_if<std::is_base_of<Base<T1, Types...>, T>::value>::type = 0>
Base& operator=(T&& other)
{
if (this != &other)
a = other.a;
return *this;
}
//assignment to other type contained in <T1, Types...>
template<typename T, typename std::enable_if<!std::is_base_of<Base<T1, Types...>, T>::value>::type = 0>
Base& operator=(T&& other)
{
// do some stuff
return *this;
}
private:
int a;
};
As you can see, I'm trying to use std::enable_if
to differentiate assignment to a Base
(move or copy) and assignment to a type by wrapping std::is_base_of
. I'm under the impression that T&&
should bind to const Base&
, Base&&
, Base&
, as well as const T&
T&&
, etc.
The problem happens when I try to create a derived class that supports the assignment by simply forwarding the arguments to the base:
class Derived : public Base<int, double>
{
public:
// similar pattern here, but call base class' operators
// for both copy/move assignment
// as well as assignment to int or double
template<typename T>
Derived& operator=(T&& other)
{
Base<int, double>::operator=(std::forward<T>(other));
return *this;
}
};
As soon as I try to do what I think should be a valid assignment, the compiler tells me that it failed to perform template deduction/substitution.
int main() {
Derived foo;
int a = 4;
foo = a;
return 0;
}
What am I doing wrong here? Please go easy on me.
Upvotes: 2
Views: 152
Reputation: 48517
Two problems:
For lvalues the forwarding-reference (as well as the template type parameter T
itself) becomes an lvalue reference. You should decay type T
prior to checking if it's a subclass of other type.
You are using std::enable_if
in a wrong way; if you want to utilize ::type = 0
syntax then it needs some other type than the default void
one.
Having that said, your std::enable_if
syntax should look as follows:
typename std::enable_if<std::is_base_of<Base<T1, Types...>
, typename std::decay<T>::type // decay of T
>::value
, int>::type = 0 // int as a second template argument
Complete example:
template<typename T, typename std::enable_if<std::is_base_of<Base<T1, Types...>, typename std::decay<T>::type>::value, int>::type = 0>
Base& operator=(T&& other)
{
if (this != &other)
a = other.a;
return *this;
}
//assignment to other type contained in <T1, Types...>
template<typename T, typename std::enable_if<!std::is_base_of<Base<T1, Types...>, typename std::decay<T>::type>::value, int>::type = 0>
Base& operator=(T&& other)
{
// do some stuff
return *this;
}
Upvotes: 5