Which function should get chosen

K

Kaba

Hi,

In the following is a short code snippet concerning the overload
resolution with function templates. Which function should be chosen in
this case (i.e. what should the program return)?

template <typename Type>
class Base {};

template <typename Type>
class A : public Base<Type> {};

template <typename Type>
int f(const Base<Type>& that) {return 0;}

template <typename Type>
int f(const Type& that) {return 1;}

int main()
{
A<int> a;
return f(a);
}

I am surprised to see that both Visual Studio 2008 and Comeau C++ both
choose the unrestricted template (return 1). I'd argue that the other
one containing Base<Type> parameter is more specialized. What is going
on?
 
G

Greg Herlihy

In the following is a short code snippet concerning the overload
resolution with function templates. Which function should be chosen in
this case (i.e. what should the program return)?

template <typename Type>
class Base {};

template <typename Type>
class A : public Base<Type> {};

template <typename Type>
int f(const Base<Type>& that) {return 0;}

template <typename Type>
int f(const Type& that) {return 1;}

int main()
{
    A<int> a;
    return f(a);
}

I am surprised to see that both Visual Studio 2008 and Comeau C++ both
choose the unrestricted template (return 1). I'd argue that the other
one containing Base<Type> parameter is more specialized. What is going
on?

The compiler does not even consider the function template with the
Base<Type> parameter, because a call to that function would require
converting the argument to a base class template-id (specifically,
converting the A<int> argument to a B<int> parameter).

Now, according to §14.8.2.1/3, this type of conversion is allowed:

"If P is a class, and P has the form template-id, then A can be a
derived class of the deduced A."

There is however one significant restriction:

"These alternatives are considered only if type deduction would
otherwise fail."

Since there is another f() function template for which type deduction
does succeed - the compiler does even consider the other f() overload
when resolving the f() function call.

Greg
 
K

Kaba

Greg said:
"If P is a class, and P has the form template-id, then A can be a
derived class of the deduced A."

"These alternatives are considered only if type deduction would
otherwise fail."

Thank you. I then have a related problem. I would like the following to
compile. However, the 0 is ambiguated because it can also be converted
to the null pointer:

template <typename Type>
class Base {};

template <typename Type>
class A
{
public:
A() {}
explicit A(const Type& that) {}
explicit A(const Type* that) {}

template <typename ThatType>
explicit A(const Base<ThatType>& that) {}
};

int main()
{
A<float> a(0);
return 0;
}

I do not want to use a cast to disambiguate in the constructor call.
Ideally, of course, the 0 shouldn't denote a null-pointer value but
there should be a special symbol for it: but's that's history. How do I
get around this?

This gives a context for the first post: I tried to use a template to
catch the type of the parameter. But that broke the Base constructor.
 
K

Kaba

Kaba said:
template <typename ThatType>
explicit A(const Base<ThatType>& that) {}

Sorry, this constructor should have been implicit:

template <typename ThatType>
A(const Base<ThatType>& that) {}
 
K

Kaba

Kaba wrote:

Ok, I was missing some more stuff. This should be a complete test case
for what I want to achieve. The constructors for which I pass a number
should run the A(const Type& that) constructor.

template <typename Type>
class Base {};

template <typename Type>
class C : public Base<Type> {};

template <typename Type>
class A
{
public:
A() {}
explicit A(const Type& that) {}
explicit A(const Type* that) {}

template <typename ThatType>
A(const Base<ThatType>& that) {}
};

int main()
{
C<float> a;
A<float> b(a);
A<float> c(0);
A<float> d(0.0);

A<int> e(0);
A<int> f(0.0);

return 0;
}
 
J

James Kanze

The compiler does not even consider the function template with
the Base<Type> parameter, because a call to that function
would require converting the argument to a base class
template-id (specifically, converting the A<int> argument to a
B<int> parameter).
Now, according to §14.8.2.1/3, this type of conversion is allowed:
"If P is a class, and P has the form template-id, then A can
be a derived class of the deduced A."
There is however one significant restriction:
"These alternatives are considered only if type deduction
would otherwise fail."
Since there is another f() function template for which type
deduction does succeed - the compiler does even consider the
other f() overload when resolving the f() function call.

I don't think that's right. The compiler applies type deduction
to both function templates, deducing Type == int for the first,
and Type == A<int> for the second. It then applies overload
resolution on the resulting functions: f( Base<int> const& )
(from the first template) and f( A< int > const& ) (from the
second template). Since the latter is a better match, it is
chosen. The choice of the "more specialize" is only used as a
tie breaker, if there would otherwise be ambiguity. That's not
the case here.
 
J

James Kanze

Thank you. I then have a related problem. I would like the
following to compile. However, the 0 is ambiguated because it
can also be converted to the null pointer:
template <typename Type>
class Base {};
template <typename Type>
class A
{
public:
A() {}
explicit A(const Type& that) {}
explicit A(const Type* that) {}
template <typename ThatType>
explicit A(const Base<ThatType>& that) {}
};
int main()
{
A<float> a(0);
return 0;
}
I do not want to use a cast to disambiguate in the constructor
call. Ideally, of course, the 0 shouldn't denote a
null-pointer value but there should be a special symbol for
it: but's that's history. How do I get around this?

Give the exact type. There's no other solution. In this case:
A<float> a( 0.0F ) ;
 

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

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top