Overloading and inheriting mix patterns

The following code prints:

generic overload 

But I wanted overload or specialization to be invoked in both cases, and not general. I am not trying to mix overload using template specialization, they are here together because no one worked as I expected. Is there any template magic for 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; } 
+4
source share
3 answers

Two ways to use type_traits to check if an argument is obtained from an 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 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"; } }; 
+5
source

To use a specialized function, the compiler needs to convert the parameters from &Impl to &Interface . When he seeks a signature matching function, exact matches are preferable to those that require conversion. Since the common foo<T> is an exact match, it wins both overload and using a specialized function.

+2
source

The template definition allows you to create a function:

 void Bar::foo<Impl>(Impl& t) 

which is better than the ones you defined that accept the Interface& parameter.

You should make the superclass function more appropriate, perhaps 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); } }; 

It doesn't seem to actually work, see http://ideone.com/IpBAv

So, you will need a type test inside the general version, looking for subclasses of Interface .

0
source

All Articles