Reputation: 3954
Say I want to write a wrapper for 2 or more classes that do the same things with different implementations and their interfaces have different function names. Depending on the context I would choose the one or the other, but I want to be able to easily switch them out. SO I write a wrapper with template specialization. Ok good. Now however I encountered a problem. My 2 classes are template classes...
If they were normal classes I could write code like this:
class A1
{
public:
int f()
{
return 1;
}
};
class A2
{
public:
int g()
{
return 1;
}
};
namespace detail
{
template <class T> int h(T& t) // general case
{
std::cout << "general" << "\n";
return t.h();
}
template <> int h<A1>(A1& a1) // case for A1
{
std::cout << "A1" << "\n";
return a1.f();
}
template <> int h<A2>(A2& a2) // case for A2
{
std::cout << "A2" << "\n";
return a2.g();
}
}
template <class T>
class Wrapper
{
public:
Wrapper(T& t) : t(t) {}
int operator()()
{
return detail::h<T>(t);
}
T& t;
};
However, how would I need to modify that code to make it run for tempalted versions of A1
and A2
? The best I came up with was this (does not compile):
template <class T>
class A1
{
public:
int f()
{
return 1;
}
};
template <class T>
class A2
{
public:
int g()
{
return 1;
}
};
namespace detail
{
template <class T, class U> int h(T<U>& t) // general case
{
return t.h();
}
template <> int h<A1<U>>(A1<U>& a1) // case for A1
{
return a1.f();
}
template <> int h<A2<U>>(A2<U>& a1) // case for A2
{
return a1.f();
}
}
template <class T, class U>
class Wrapper
{
public:
Wrapper(T<U>& t) : t(t) {}
int operator()()
{
return detail::h<T,U>(t);
}
T<U>& t;
};
So, I somehow need to template the template specializations, which sounds like a contradiction.
Ok.. trying to make the overload solution work, but I don't really get it...
template <template <typename> class T, class U>
class Wrapper
{
public:
Wrapper(T<U>& t) : t(t) {}
template <template <typename> class T, typename U>
int h(T<U>& t) // general case
{
return t.h();
}
template <typename U>
int h(A1<U>& a1) // case for A1
{
return a1.f();
}
template <typename U>
int h(A2<U>& a2) // case for A2
{
return a2.g();
}
T<U>& t;
};
Upvotes: 1
Views: 74
Reputation: 25536
Prefer overload to template specialisation:
template <template <typename> class T, typename U>
int h(T<U>& t) // general case
{
return t.h();
}
template <typename T>
int h(A1<T>& a1) // case for A1
{
return a1.f();
}
template <typename T>
int h(A2<T>& a2) // case for A2
{
return a2.g();
}
Upvotes: 4