Function template + overloading + polymorphism

I

Imre

Why is the function template a better match for the call in the
following code?

And how could I write a version of F() that should be called if the
argument is a pointer to a type that is derived from B, while the
template version should be called for all other argument types?

#include <iostream>

using namespace std;

struct B {};
struct D: public B {};

template <typename T>
int F(T &t) { return 1; }
int F(B *pb) { return 2; }

int main(int argc, char* argv[])
{
D *pd = new D;
int i = F(pd);
cout << i << '\n'; // writes 1 (VC++ 7.1), I'd like to get 2
return 0;
}

Thanks.

Imre
 
H

Howard Hinnant

Imre said:
Why is the function template a better match for the call in the
following code?

And how could I write a version of F() that should be called if the
argument is a pointer to a type that is derived from B, while the
template version should be called for all other argument types?

#include <iostream>

using namespace std;

struct B {};
struct D: public B {};

template <typename T>
int F(T &t) { return 1; }
int F(B *pb) { return 2; }

int main(int argc, char* argv[])
{
D *pd = new D;
int i = F(pd);
cout << i << '\n'; // writes 1 (VC++ 7.1), I'd like to get 2
return 0;
}

The template is a better match because:

int F<D*>(D*&);

is a better match for a D* argument than:

int F(B*);

(no conversion from D* to B* required for the former.

If you have access to the incredibly useful utilities enable_if and
is_convertible (maybe look at www.boost.org) you could do something like
the listing below. I'm using Metrowerks which has these facilities
built in, and spells enable_if as restrict_to, and that's what I'm
posting so that I can post tested code:

#include <iostream>

using namespace std;

struct B {};
struct D: public B {};

template <typename T>
typename Metrowerks::restrict_to
<
!Metrowerks::is_convertible said:
F(T &t) { return 1; }

int F(B *pb) { return 2; }

int main(int argc, char* argv[])
{
D *pd = new D;
int i = F(pd);
cout << i << '\n'; // writes 2 for me
return 0;
}

-Howard
 
V

Victor Bazarov

Imre said:
Why is the function template a better match for the call in the
following code?

Essentially, F<> is a better match because it deduces that T is
'D*' and since the forma argument is a reference and the actual
argument is an l-value, there is no conversion involved. For the
F(B*) a derived-to-base conversion (standard conversion) is needed.
No conversion is preferred to any conversion.
And how could I write a version of F() that should be called if the
argument is a pointer to a type that is derived from B, while the
template version should be called for all other argument types?

I am not sure you can.

If your intention is to somehow figure out that the type you have
('D' in your case) is a derived type of 'B', then you just neen to
look at the 'is_base_and_derived' template from Boost library.
#include <iostream>

using namespace std;

struct B {};
struct D: public B {};

template <typename T>
int F(T &t) { return 1; }
int F(B *pb) { return 2; }

int main(int argc, char* argv[])
{
D *pd = new D;
int i = F(pd);
cout << i << '\n'; // writes 1 (VC++ 7.1), I'd like to get 2
return 0;
}

V
 
K

Kostas Katsamakas

Imre said:
Why is the function template a better match for the call in the
following code?

And how could I write a version of F() that should be called if the
argument is a pointer to a type that is derived from B, while the
template version should be called for all other argument types?

#include <iostream>

using namespace std;

struct B {};
struct D: public B {};

template <typename T>
int F(T &t) { return 1; }
int F(B *pb) { return 2; }

int main(int argc, char* argv[])
{
D *pd = new D;
int i = F(pd);
cout << i << '\n'; // writes 1 (VC++ 7.1), I'd like to get 2
return 0;
}

Thanks.

Imre
i suppose you could do something like this:

template <typename T>

int F(T &t)
{
T *pt = &t;
B *pB = dynamic_cast<T*>(pt);
if(pB)
{
return F(pB);// Calls F(B *pB);
}
}

I'm not sure it works. I didn't test it.
Remeber to turn on the Run Time Type Information to your compiler.
If you use VC++ 7.1 it's somewhere in the Compiler setting
 
K

Kostas Katsamakas

Kostas said:
Imre said:
Why is the function template a better match for the call in the
following code?

And how could I write a version of F() that should be called if the
argument is a pointer to a type that is derived from B, while the
template version should be called for all other argument types?

#include <iostream>

using namespace std;

struct B {};
struct D: public B {};

template <typename T>
int F(T &t) { return 1; }
int F(B *pb) { return 2; }

int main(int argc, char* argv[])
{
D *pd = new D;
int i = F(pd);
cout << i << '\n'; // writes 1 (VC++ 7.1), I'd like to get 2
return 0;
}

Thanks.

Imre
i suppose you could do something like this:

template <typename T>

int F(T &t)
{
T *pt = &t;
B *pB = dynamic_cast<T*>(pt);
if(pB)
{
return F(pB);// Calls F(B *pB);
}
}

I'm not sure it works. I didn't test it.
Remeber to turn on the Run Time Type Information to your compiler.
If you use VC++ 7.1 it's somewhere in the Compiler setting

I made a mistake above.
the correct line is :
B *pB = dynamic_cast<B*>(pt);
 

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
474,202
Messages
2,571,055
Members
47,659
Latest member
salragu

Latest Threads

Top