The following code prints:
generic
overload
But what I wanted is that the overload or the specialization were called in both cases, not the generic one. I'm not trying to mix overloading with template specialization, they're here together because none worked as I expected. Is there any template magic to accomplish this?
#include <iostream>
class Interface {};
class Impl: public Interface {};
class Bar
{
public:
template<typename T> void foo(T& t) {
std::cout << "generic\n";
}
void foo(Interface& t) {
std::cout << "overload\n";
}
};
template<> void Bar::foo<Interface>(Interface& t) {
std::cout << "specialization\n";
}
int main() {
Bar bar;
Impl impl;
Interface& interface = impl;
bar.foo(impl);
bar.foo(interface);
return 0;
}开发者_高级运维
Two ways using type_traits
to test if the argument is derived from Interface.
#include <boost/type_traits.hpp>
class Interface {};
class Impl: public Interface {};
class Bar
{
template <class T> void foo_impl(T& value, boost::false_type)
{
std::cout << "generic\n";
}
void foo_impl(Interface& value, boost::true_type)
{
std::cout << "Interface\n";
}
public:
template<typename T> void foo(T& t) {
foo_impl(t, boost::is_base_of<Interface, T>());
}
};
Or disable the template if the condition is met, leaving only the non-template as a candidate.
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>
class Interface {};
class Impl: public Interface {};
class Bar
{
public:
template<typename T>
typename boost::disable_if<boost::is_base_of<Interface, T>, void>::type foo(T& t)
{
std::cout << "generic\n";
}
void foo(Interface&)
{
std::cout << "Interface\n";
}
};
In order to use the specialized function, the compiler would need to do a parameter conversion from &Impl
to &Interface
. When it's looking for a function signature match, exact matches are preferred over ones that require a conversion. Since the generic foo<T>
is an exact match, it wins out over both the overload and the specialized function.
The template definition allows a function to be created:
void Bar::foo<Impl>(Impl& t)
which is a better match than the ones you defined which take an Interface&
parameter.
You have to make the superclass function a better match, possibly like this:
class Bar
{
struct fallback { fallback(int) {} };
template<typename T> void foo(T& t, fallback) {
std::cout << "generic\n";
}
void foo(Interface& t, int) {
std::cout << "overload\n";
}
public:
template<typename T> void foo(T& t) {
foo(t, 0);
}
};
Doesn't seem to actually work though, see http://ideone.com/IpBAv
So you'd need a type test inside the generic version, looking for subclasses of Interface
.
精彩评论