Hi I'm having problems selecting the correct version of a templated class which has an explicit specialization. I'm wanting to select a specialization using a derived class of the class used to specialize. The scenario is:
#include <stdio.h>
class A
{};
class B: public A
{};
template<typename T>
class Foo
{
public:
int FooBar(void) { return 10; }
};
// Explicit specialization for A
template<> int Foo< A >::FooBar( void ) { return 20; }
void main( void)
{
Foo<B> fooB;
// This prints out 10 instead of wanted 20 ie compiler selects the general version
printf("%d", fooB.FooBar() );
}
As I say in my comments there I want to see 20 being printed out because B is derived from A but 10 gets printed out instead. How do I go about getting the specialization called without resorting to writing a specialization for each and every derived class (my actual scenario has a lot of derived types).
---EDIT : NEW ANSWER Let's make the original approach more maintainable. All the important choices can be found in the definition of Foo. It is supposed to be easy to maintain.
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <iostream>
class A
{};
class B: public A
{};
class C{};
class D : public C{};
class E{};
struct DefaultMethod
{
static int fooBar() { return 10; }
};
struct Method1
{
static int fooBar() { return 20; }
};
struct Method2
{
static int fooBar() { return 30; }
};
template<typename T, typename BaseClass, typename Choice1, typename OtherChoice>
struct IfDerivesFrom :
boost::mpl::if_<
typename boost::is_base_of<BaseClass, T>::type,
Choice1,
OtherChoice>::type
{
};
template<typename T>
struct Foo :
IfDerivesFrom<T, A,
Method1,
IfDerivesFrom<T, C,
Method2,
DefaultMethod>
>
{
};
int main()
{
std::cout << Foo<A>::fooBar() << std::endl;
std::cout << Foo<B>::fooBar() << std::endl;
std::cout << Foo<C>::fooBar() << std::endl;
std::cout << Foo<D>::fooBar() << std::endl;
std::cout << Foo<E>::fooBar() << std::endl;
return 0;
}
---ORIGINAL ANSWER If you can use boost, you can do something like the following :
#include <boost/type_traits/is_base_of.hpp>
template<bool b>
class FooHelper
{
int FooBar();
};
template<> FooHelper<true>::FooBar(){ return 20;}
template<> FooHelper<false>::FooBar(){ return 10;}
template<typename T>
class Foo
{
public:
int FooBar(void) { return FooHelper<boost::is_base_of<A, T>::type::value>(); }
};