Function overloading

F

Frank Neuhaus

Hi
I am trying to overload a function for several types and I have
encountered some problems.
Below is the program I am considering:

#include <iostream>
#include <string>

struct Base {};

class Derived : public Base {};

class SomeClass {};

void f(int t)
{
std::cout << "int" << std::endl;
}

void f(const Base* t)
{
std::cout << "base" << std::endl;
}

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

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

int main()
{
f(5); // expecting "int"

Base b;
f(&b); // expecting "base"
Derived d;
f(&d); // expecting "base"

SomeClass c;
f(c); // expecting "cref"

std::string test="test";
f(test); // expecting "string"
};


I want the call f(&b) and f(&d) to result in the output "base". What I
am getting is the result "cref" for both calls. The compiler appears
to prefer making T=Base*, and T=Derived* respectively in the template
function. What do I need to change in order to make this result in the
desired output? What exactly are the internal rules of the compiler
for function overloading - i.e in which cases does it prefer which of
the overloads?

Thank you very much
 
A

Andrey Tarasevich

Frank said:
...
void f(const Base* t)
{
std::cout << "base" << std::endl;
}

template<typename T>
void f(const T& t)
{
std::cout << "cref" << std::endl;
};
...

int main()
{
> ...
Base b;
f(&b); // expecting "base"

In this case the candidates are

void f(const Base* t);
void f(Base* const& t); // specialized from template

while the argument type is 'Base*'. The first candidate requires a
qualification conversion 'Base* -> const Base*'. The second candidate
requires a direct reference binding, which is considered an identity
conversion (see 13.3.3.1.4/1). Identity conversion sequence is
considered a subsequence of any other non-identity conversion sequence
(13.3.3.2/3), and for this reason reference binding it is "better" than
qualification conversion. The compiler has to choose the second variant
(i.e. specialize the template).
Derived d;
f(&d); // expecting "base"

Virtually the same thing here. The candidates are

void f(const Base* t);
void f(Derived* const& t); // specialized from template

For the first variant a derived-to-base conversion is needed, which has
even higher rank than a qualification conversion. For the second one, a
direct reference binding works. And wins the resolution.
I want the call f(&b) and f(&d) to result in the output "base". What I
am getting is the result "cref" for both calls. The compiler appears
to prefer making T=Base*, and T=Derived* respectively in the template
function. What do I need to change in order to make this result in the
desired output?

Well, what can you change? Get rid of the template, for example...
 
F

Frank Neuhaus

Ok thank you both very much for your two replies. Realizing that it
appears to be impossible to make the compiler call an overload where a
conversion (Derived*->Base*) is needed in presence of a template
function, I went to look for something else... I found boost type
traits quite helpful. It looks like this now - just FYI :) :

// note that I am not interested in T=pointers that are not derived by
Base

void f(int t)
{
std::cout << "int" << std::endl;
}

template<typename T>
void f_ptr(const T& t, const boost::false_type&)
{
std::cout << "cref" << std::endl;
}

void f_ptr(const Base* t, const boost::true_type&)
{
std::cout << "base" << std::endl;
}

template<typename T>
void f(const T& t)
{
f_ptr(t,boost::is_pointer<T>());
};

void f(const std::string& t)
{
std::cout << "string" << std::endl;
};
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,149
Members
46,695
Latest member
StanleyDri

Latest Threads

Top