user1899020
user1899020

Reputation: 13575

How to use class template specialization in its subclass?

I have a class template as following:

template<class T>
class A;

And when T is a Pair<T1, T2>, I specialize it.

template<class T1, class T2>
class A<Pair<T1, T2>>;

And I have a class which is derived from a Pair

class D : public Pair<int, char>
{};

When I use A<D>, I hope it uses the specialized version but it doesn't. I have many classes derived from Pair or other specialized version. How to do it automatically?

Upvotes: 1

Views: 545

Answers (2)

aaronman
aaronman

Reputation: 18750

The reason it didn't work is because you specialized it for pair, not your class that inherits from pair (BTW generally a bad idea to inherit from stdlib classes). You could specialize it for D.

template<class T>                                                                  
struct A {                                                                         
    A(){cout << "not special\n";}                                                  
};                                                                                 

template<class T1, class T2>                                                       
struct A<pair<T1, T2>> {                                                           
    A(){cout << "special\n";}                                                      
};                                                                                 

struct D : public pair<int, char>                                                  
{};                                                                                

template<>                                                                         
struct A<D> {                                                                      
    A(){cout << "special D\n";}                                                    
};                                                                                 

int main() {                                                                       
    A<D> a;                                                                        
    return 0;                                                                      
}  

Outputs special D

You can also use std::is_base_of but it's gonna be a pain and I recommend against it. If your deadset on doing it you can have another class like this

template <typename T, bool B>
struct helper;                                                                         

template <typename T>
struct helper<T,true>;

template <typename T>
struct helper<T,true>;

Then you can create that class inside the first one like

template<class T>                                                                  
struct A {
    helper<T,is_base_of<pair<int,char>,T>::value> h;
};

That should get you started I'll let you figure out the rest :).

Here's a more concise version with only one class.

template<class T,bool B = is_base_of<pair<int,char>,T>::value>                     
struct A;                                                                          

template<class T>                                                                  
struct A<T,true> {                                                                 
    A(){cout << "special\n";}                                                      
};                                                                                 

struct D : public pair<int, char>                                                  
{};                                                                                

template<class T>                                                                  
struct A<T,false> {                                                                
    A(){cout << "not special\n";}                                                  
};                                                                                 

int main() {                                                                       
    A<D> a;                                                                        
    A<int> b;                                                                      
    return 0;                                                                      
}  

Upvotes: 1

Koushik Shetty
Koushik Shetty

Reputation: 2176

"Never derive from std types, they are not meant to be derived. Deriving may cause UB"

D is a different type than pair<int,char>(although derived from it). Template argument deduction does not take into account the conversion ability between types. it only matches types.

Now to your case where you want to call the specialized version you can use tag dispatch and a helper.

following code might help you :

template<class T>                   //Primary class template
class A
{//impl..};


template<class T1, class T2>       //explicit specialization
class A<pair<T1, T2>>
{
public:
A(){std::cout << "A<pair>\n";}
};


template<typename T1,typename T2, bool b>  //type selector utility, dispatched to this
struct AP{typedef A<T1> type;};            // type if passed type is not a 
                                           //derived class of pair.


template<typename T1,typename T2>
struct AP<T1,T2,std::true_type::value>
{
    typedef A<pair<T1,T2>> type;    //only if passed type is derived from pair
};



class D : public pair<int, char>
{};                                    //type derived from pair


class E{};                             //some other type

template<typename pair,typename t>      //helper class to do the dirty job
struct APH
{
    using fsttyp = typename pair::first_type;
    using sndtyp = typename pair::second_type;
    typedef typename AP<fsttyp,sndtyp,is_base_of<pair,t>::value>::type type;
};            

int main()
{

    APH<pair<int,char>,D>::type a;// a is of A<pair<int,char>> type
    APH<pair<int,char>,E>::type a;// a is of A<E> type
    return 0;
}

Upvotes: 1

Related Questions