Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template function overload for base class [duplicate]

How do I force compiler to pick up a template function overload for a base class?

Here is an example that illustrates the question

#include <iostream>

class A
{};

class B : public A
{};

template <class T>
void f (const T& t)
{
    std::cout << "Generic f" << std::endl;
}

void f (const A& a)
{
    std::cout << "Overload for A" << std::endl;
}

template <class T>
void call_f (const T& t)
{
    f (t);  
}

int main() 
{
    call_f (10);
    call_f (A());
    call_f (B());

    return 0;
}

It produces the output

Generic f
Overload for A
Generic f

Why doesn't the compiler pick up f (const A&) in the 3rd case? UPD: OK, this one is clear void f<B> (const B&) is better than void f (const A&), but I'm still looking for answer to the 2nd question.

And is it possible to force it to do so without casting B to A?

like image 833
cppalex Avatar asked Jun 18 '14 16:06

cppalex


People also ask

Can template function be overloaded?

You may overload a function template either by a non-template function or by another function template. The function call f(1, 2) could match the argument types of both the template function and the non-template function.

Can we have overloading of the function templates clear response?

Explanation: Template function cannot be overloaded as done in this program.

What is difference between function template and overloaded?

Function overloading is used when multiple functions do similar operations; templates are used when multiple functions do identical operations. Templates provide an advantage when you want to perform the same action on types that can be different.

How many times is the template class instantiated?

Template instantiation has two forms: explicit instantiation and implicit instantiation.


1 Answers

Using call_f(B()) results in a call to `f() which is best matched by the template version. For the non-template version a conversion is required. As a result, the template is chosen. If the template and the non-template would be equally good options, the non-template would be preferred.

If you want to the non-template to be called, you'll need to make the template a non-option. for example, the template could be implemented like

#include <type_traits>
template <class T>
typename std::enable_if<!std::is_base_of<A, T>::value>::type f(T const&)
{
    std::cout << "Generic f\n";
}

If C++11 can't be used you could either implement a version of std::is_base_of<...>, use a version from Boost or use a simple dispatch:

struct true_type {};
struct false_type {};

true_type A_is_base_of(A const*) { return true_type(); }
false_type A_is_base_of(void const*) { return false_type(); }

template <class T>
void f (T const&, false_type)
{
    std::cout << "Generic f\n";
}

void f (A const&, true_type)
{
    std::cout << "Overload for A\n";
}

template <class T>
void call_f (const T& t)
{
    f (t, A_is_base_of(&t));  
}
like image 182
Dietmar Kühl Avatar answered Oct 28 '22 07:10

Dietmar Kühl