Search code examples
c++templatesinheritancepartial-specialization

Partial specialization with a non-template class which is inherited from a template class


Example 1

If we have Base and Derived classes

class Base
{};
class Derived : public Base
{};

and a template class

template <class T, class Enabler=void>
class Partialy
{
public:
    void say()
    {
        std::cout << "Partialy Default" << std::endl;
    }
};

We can write a partial specialization next way:

template <class T>
class Partialy<T, typename std::enable_if<std::is_base_of< Base, T >::value>::type>
{
public:
    void say()
    {
        std::cout << "Partialy special" << std::endl;
    }
};

Example 1 will work OK. (Full code: http://ideone.com/4FyrD )

Example 2

If only I make Base class template one:

template <class T>
class BaseTpl
{};
class DerivedTpl : public BaseTpl<int>
{};

The next partial specializetion don't work:

template <class T, class Ta>
class Partialy<T, typename std::enable_if<std::is_base_of< BaseTpl<Ta>, T >::value>::type>
{
public:
    void say()
    {
        std::cout << "Partialy special with TPL" << std::endl;
    }
};

Example 2 won't compile The compiler throws an error "template parameters not used in partial specialization:" (Full code: http://ideone.com/gZ6J2 )

Question

So the question is. Is there any way to write partial specializaion which would work for all classes which are derived from BaseTpl.

The list of classes for which the specialization shold work:

class A1 : public BaseTpl<int>
class A2 : public BaseTpl<std::string>
class A3 : public BaseTpl<vector<int> >
...

Solution

  • The way you have it, it is impossible for the compiler to match the Ta against any type. Imagine you had this:

    class DerivedTpl : public BaseTpl<int>, public BaseTpl<char>
    {};
    

    What type will Ta be when it tries to match?

    For your particular problem, one solution is to introduce an all-encompassing base class above BaseTpl:

    class BaseNonTpl {};
    
    template <class T>
    class BaseTpl : BaseNonTpl
    {};
    

    Then, modify the partial specialisation to look for that base class instead.

    template <class T>
    class PartialyTpl<T, typename std::enable_if<std::is_base_of< BaseNonTpl, T >::value>::type>
    

    That way, the compiler doesn't have to try and figure out what base class you meant to use.