Roddy
Roddy

Reputation: 68023

Function template and regular overloads

The following code has a couple of regular function overloads, and - now - a template function intended as a catch-all if no overload is suitable.

It almost works as I want, except that using derived classes (which previously ended up in the regular overload) get handled by the function template instead.

#include <iostream>

class Base { };
class AnotherBase { };

class Derv : public Base{ };

class Derv2 : public Base { };

class DervDerv : public Derv { };

void f(const Base &b)
{
  printf("b(Base)\n");
}

void f(const Derv &b)
{
  printf("b(Derv)\n");
}

template<class T> void f(const T& t)
{
  printf("b(template)\n");  
}

int main() {
    f(Base());
    f(AnotherBase());
    f(Derv());
    f(Derv2());
    f(DervDerv());

    return 0;
} 

So the output I get is this...

b(Base)
b(template)
b(Derv)
b(template)
b(template)

... when what I'd naively expected was this:

b(Base)
b(template)
b(Derv)
b(Base)
b(Derv)

Is a function overload of a base class really ranked as "lower quality" than a function template? If so, is there an easy way to change this?

https://ideone.com/jD2lgz

Upvotes: 2

Views: 60

Answers (1)

It's not about "quality". It's about conversions, just like it is with any other overload. To do overload resolution on the call to f(Derv2());, a compiler will synthesize a declaration like this one from your function template:

void f(const Derv2& t);

Which it pits against the other declared overloads. This overload gets picked for the exact same reason f(const Derv &) is a better match than f(const Base &) when you write f(Derv());.

A "catch-all" template will do just that, it will catch everything for which there isn't an exact user-defined overload. If you want to prevent that, you need to constrain the template with meta programming. A simple trick that relies on SFINAE would look like this:

template<class T>
auto f(const T& t) -> std::enable_if_t<!std::is_convertible<T*, Base*>::value>
{
  printf("b(template)\n");  
}

That produces the exact output you expected. Though obviously, you'd need to know what to constrain against in advance.

Upvotes: 2

Related Questions