Reputation: 768
Let's say I have a pure abstract base class. A class template implements this interface, and is specialized. Now, my issue is that this specialization should be able to handle subclasses of the specialization. So, I tried enable_if, but then the subclass ends up being abstract... How can I get around this?
By example:
// This example doesn't work because a subclass of A does not satisfy the
// specialization for B<T>::foo()
class A {
public:
virtual void foo() = 0;
};
template <class T>
class B : public A {
...
public:
...
void foo();
...
};
void B::foo() {
...
}
template <>
void B<A>::foo() {
...
}
class C : A {
...
public:
...
void foo();
...
};
int main() {
B<C> bar; // I was like "this is gonna work!! :) :D"
bar.foo(); // But this calls B::foo() instead of B<A>::foo()... :'( *sob*
}
And another example:
// This example doesn't work because B ends up being abstract
class A {
public:
virtual void foo() = 0;
};
template <class T>
class B : public A {
...
public:
...
template <class U=T>
typename std::enable_if<!std::is_base_of<U, A>::value, void>::type
foo() {
...
}
template <class U=T>
typename std::enable_if<std::is_base_of<U, A>::value, void>::type
foo() {
...
}
};
class C : A {
...
public:
...
void foo();
...
};
int main() {
// I got excited thinking this would work \(^.^)/
B<C> bar; // and then it didn't because B is abstract /(-_-)\ ...
bar.foo();
}
Any ideas on how to solve this? Thanks!!
Upvotes: 2
Views: 4020
Reputation: 137310
B<C>
and B<A>
are distinct types, so your first case will never work.
What you want to do is to specialize the template for all classes T
for which std::is_base_of<A, T>::value
is true
. For that, use a default template parameter with partial specialization:
template <class T, bool = std::is_base_of<A, T>::value>
class B : public A {
public:
void foo() override { std::cout << "A is not base of T!" << std::endl; }
};
template <class T>
class B<T, true> : public A {
public:
void foo() override { std::cout << "A is base of T!" << std::endl; }
};
When A is a base of T, the bool
parameter is true
so the partial specialization is used. Otherwise, the base template is used.
Note that is_base_of
will return true
even if A
is an inaccessible base of T
, so you may also want to add a is_convertible<T*, A*>
check.
Demo.
Upvotes: 8