Reputation: 13575
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
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
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