Connecting Tech Pros Worldwide Forums | Help | Site Map

Function template + overloading + polymorphism

Imre
Guest
 
Posts: n/a
#1: Jul 23 '05

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


Howard Hinnant
Guest
 
Posts: n/a
#2: Jul 23 '05

re: Function template + overloading + polymorphism


In article <1110035461.848248.135370@o13g2000cwo.googlegroups .com>,
"Imre" <jrms@pager.hu> wrote:
[color=blue]
> 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;
> }[/color]

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<T, B*>::value,
int[color=blue]
>::type[/color]
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
Victor Bazarov
Guest
 
Posts: n/a
#3: Jul 23 '05

re: Function template + overloading + polymorphism


"Imre" <jrms@pager.hu> wrote...[color=blue]
>
> Why is the function template a better match for the call in the
> following code?[/color]

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.
[color=blue]
> 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?[/color]

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.
[color=blue]
> #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;
> }[/color]

V


Kostas Katsamakas
Guest
 
Posts: n/a
#4: Jul 23 '05

re: Function template + overloading + polymorphism


Imre wrote:
[color=blue]
>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
>
>
>[/color]
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
Kostas Katsamakas
Guest
 
Posts: n/a
#5: Jul 23 '05

re: Function template + overloading + polymorphism


Kostas Katsamakas wrote:
[color=blue]
> Imre wrote:
>[color=green]
>> 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
>>
>>
>>[/color]
> 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[/color]

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