1

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?

user1899020
  • 13,167
  • 21
  • 79
  • 154

2 Answers2

1

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;                                                                      
}  
aaronman
  • 18,343
  • 7
  • 63
  • 78
1

"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;
}
Koushik Shetty
  • 2,146
  • 4
  • 20
  • 31
  • Is it in the standard that it can cause UB, it's well known that you shouldn't do it of course but I didn't know it could cause UB – aaronman Oct 05 '13 at 07:06
  • Did a little searching looks like your wrong about the UB [(link)](http://stackoverflow.com/questions/4353203/thou-shalt-not-inherit-from-stdvector), the only time it could cause a problem is object slicing because the destructors are not virtual in the stdlib – aaronman Oct 05 '13 at 07:18
  • @aaronman i'm not wrong about UB. i said it may cause UB. if for some reason you are using a pointer to base class and pointing at a derived type at runtime then your derived is not destroyed. there is no harm otherwise. but one does not know the useage. – Koushik Shetty Oct 05 '13 at 07:28
  • Yada yada. Too bad some std classes are intended to be derived from. And 'no virtual destructor' argument isn't specific to standard lib. – jrok Oct 05 '13 at 11:07