template overload resolution

V

Victor Bazarov

hurcan said:
given the code snippet;

template<typename T>
void foo(T,T){}

template<typename T1,typename T2>
void foo(T1*,T2*){}

int main( ) {

foo((int*)0,(int*)0);

}

Could anyone please explain me why the second template is not more
viable for overload resolution?
AFAIK each argument is matched with corresponding parameter. in that
case shouldnt T1* and T2* match better than T for (int*)? I assume T1
and T2 are disjoint aren't they? or must they be different types?

A template with fewer arguments is considered more specialised than one
with more arguments, I guess. The more arguments a template has, the
more generic it is.

Those are just guesses, of course. I don't have time to look through
the Standard for confirmation.

V
 
H

hurcan solter

given the code snippet;

template<typename T>
void foo(T,T){}

template<typename T1,typename T2>
void foo(T1*,T2*){}

int main( ) {

foo((int*)0,(int*)0);

}

Could anyone please explain me why the second template is not more
viable for overload resolution?
AFAIK each argument is matched with corresponding parameter. in that
case shouldnt T1* and T2* match better than T for (int*)? I assume T1
and T2 are disjoint aren't they? or must they be different types?

Thanks in advance.
 
H

hurcan solter

A template with fewer arguments is considered more specialised than one
with more arguments, I guess. The more arguments a template has, the
more generic it is.

Those are just guesses, of course. I don't have time to look through
the Standard for confirmation.
Well, in fact the call is ambiguous.it's unambiguous if i define
foo(T*,T*)
which suggests that,there is also a relation between argument that it
prevents from
one preferred over another.
 
V

Victor Bazarov

Hendrik said:
hurcan solter said:
given the code snippet;

template<typename T>
void foo(T,T){}

template<typename T1,typename T2>
void foo(T1*,T2*){}

int main( ) {

foo((int*)0,(int*)0);

}

Could anyone please explain me why the second template is not more
viable for overload resolution?
[...]

From <http://www.comeaucomputing.com/tryitout/>:

Comeau C/C++ 4.3.9 (Mar 27 2007 17:24:47) for ONLINE_EVALUATION_BETA1
Copyright 1988-2007 Comeau Computing. All rights reserved.
MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 9: error: more than one instance of overloaded
function "foo"
matches the argument list, the choices that match are:
function template "void foo(T, T)"
function template "void foo(T1 *, T2 *)"
The argument types that you used are: (int *, int *)
foo((int*)0,(int*)0);
^

1 error detected in the compilation of "ComeauTest.c".
Thanks in advance.

HTH,

Schobi

Could you perhaps enlighten us how this explains *why* the second
template is *not* more viable?

Thanks!

V
 
H

Hendrik Schober

Victor Bazarov said:
Hendrik said:
hurcan solter said:
given the code snippet;

template<typename T>
void foo(T,T){}

template<typename T1,typename T2>
void foo(T1*,T2*){}

int main( ) {

foo((int*)0,(int*)0);

}
[...]

From <http://www.comeaucomputing.com/tryitout/>:

Comeau C/C++ 4.3.9 (Mar 27 2007 17:24:47) for ONLINE_EVALUATION_BETA1
Copyright 1988-2007 Comeau Computing. All rights reserved.
MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 9: error: more than one instance of overloaded
function "foo"
matches the argument list, the choices that match are:
function template "void foo(T, T)"
function template "void foo(T1 *, T2 *)"
The argument types that you used are: (int *, int *)
foo((int*)0,(int*)0);
^

1 error detected in the compilation of "ComeauTest.c".
Thanks in advance.

HTH,

Schobi

Could you perhaps enlighten us how this explains *why* the second
template is *not* more viable?

I don't think I can.
I /guessed/ neither specialization to be more viable.
I tried Comeau and found it agreeing with my guess.
So I posted Comeau's opinion on the matter. (When I
did this, my news server didn't have your reply yet,
so I wasn't trying to contradict you.)

Schobi

--
(e-mail address removed) is never read
I'm HSchober at gmx dot de
"If there were some arcane way to remove the heads of every
newsgroup troll on the planet, I think it would elevate
humans to a whole new level of intelligence."
Rocky Frisco
 
H

Hendrik Schober

hurcan solter said:
given the code snippet;

template<typename T>
void foo(T,T){}

template<typename T1,typename T2>
void foo(T1*,T2*){}

int main( ) {

foo((int*)0,(int*)0);

}

Could anyone please explain me why the second template is not more
viable for overload resolution?
[...]

From <http://www.comeaucomputing.com/tryitout/>:

Comeau C/C++ 4.3.9 (Mar 27 2007 17:24:47) for ONLINE_EVALUATION_BETA1
Copyright 1988-2007 Comeau Computing. All rights reserved.
MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 9: error: more than one instance of overloaded
function "foo"
matches the argument list, the choices that match are:
function template "void foo(T, T)"
function template "void foo(T1 *, T2 *)"
The argument types that you used are: (int *, int *)
foo((int*)0,(int*)0);
^

1 error detected in the compilation of "ComeauTest.c".
Thanks in advance.

HTH,

Schobi

--
(e-mail address removed) is never read
I'm HSchober at gmx dot de
"If there were some arcane way to remove the heads of every
newsgroup troll on the planet, I think it would elevate
humans to a whole new level of intelligence."
Rocky Frisco



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
V

Victor Bazarov

Hendrik said:
Victor Bazarov said:
Hendrik said:
given the code snippet;

template<typename T>
void foo(T,T){}

template<typename T1,typename T2>
void foo(T1*,T2*){}

int main( ) {

foo((int*)0,(int*)0);

}
[...]

From <http://www.comeaucomputing.com/tryitout/>:

Comeau C/C++ 4.3.9 (Mar 27 2007 17:24:47) for
ONLINE_EVALUATION_BETA1 Copyright 1988-2007 Comeau Computing. All
rights reserved. MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 9: error: more than one instance of overloaded
function "foo"
matches the argument list, the choices that match are:
function template "void foo(T, T)"
function template "void foo(T1 *, T2 *)"
The argument types that you used are: (int *, int *)
foo((int*)0,(int*)0);
^

1 error detected in the compilation of "ComeauTest.c".

Thanks in advance.

HTH,

Schobi

Could you perhaps enlighten us how this explains *why* the second
template is *not* more viable?

I don't think I can.
I /guessed/ neither specialization to be more viable.
I tried Comeau and found it agreeing with my guess.
So I posted Comeau's opinion on the matter. (When I
did this, my news server didn't have your reply yet,
so I wasn't trying to contradict you.)

Please do contradict, I am all for a healthy discussion. Besides, my
answer was just a guess, I am not even sure it is correct unless it's
confirmed or proven wrong.

The reason I am asking is that it seems that your reply is essentially
giving the answer "because Comeau C++ says it is" to the 'why' question.
My understanding is that the OP had already found out that the second
function template was not more viable, you simply confirmed what the OP
already knew, *OR* I misunderstood something (which happens more often
as I grow older, unfortunately), and then I need to be shown the light.

V
 
H

Hendrik Schober

Victor Bazarov said:
Hendrik said:
Victor Bazarov said:
Hendrik Schober wrote:
given the code snippet;

template<typename T>
void foo(T,T){}

template<typename T1,typename T2>
void foo(T1*,T2*){}

int main( ) {

foo((int*)0,(int*)0);

}

[...]

From <http://www.comeaucomputing.com/tryitout/>:

Comeau C/C++ 4.3.9 (Mar 27 2007 17:24:47) for
ONLINE_EVALUATION_BETA1 Copyright 1988-2007 Comeau Computing. All
rights reserved. MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 9: error: more than one instance of overloaded
function "foo"
matches the argument list, the choices that match are:
function template "void foo(T, T)"
function template "void foo(T1 *, T2 *)"
The argument types that you used are: (int *, int *)
foo((int*)0,(int*)0);
^

1 error detected in the compilation of "ComeauTest.c".

Thanks in advance.

HTH,

Schobi

Could you perhaps enlighten us how this explains *why* the second
template is *not* more viable?

I don't think I can.
I /guessed/ neither specialization to be more viable.

These aren't specializations, but overloaded
functions. (No partial specialization of
function templates. I know. Damn.)
Please do contradict, I am all for a healthy discussion. Besides, my
answer was just a guess, I am not even sure it is correct unless it's
confirmed or proven wrong.

My answer was just a guess, tooI wouldn't know chapter
and verse, but this

template<typename T>
void foo(T,T){}

template<typename T1,typename T2>
void foo(T1*,T2*){}

int main()
{
foo((int*)0,(int*)0);
}

looks to me as if neither overloaded version is
a better fit than the other -- which is why I
asked Comeau to confirm. .
The reason I am asking is that it seems that your reply is essentially
giving the answer "because Comeau C++ says it is" to the 'why' question.
My understanding is that the OP had already found out that the second
function template was not more viable, you simply confirmed what the OP
already knew, *OR* I misunderstood something (which happens more often
as I grow older, unfortunately), and then I need to be shown the light.

I'm sorry I wasn't making my opinion clearer. I
assumed that neither function template was a
better fit. I thought posting an error message
that says exactly that would make that clear. I
should probably have been more explicit, though.

Schobi

--
(e-mail address removed) is never read
I'm HSchober at gmx dot de
"If there were some arcane way to remove the heads of every
newsgroup troll on the planet, I think it would elevate
humans to a whole new level of intelligence."
Rocky Frisco
 
J

James Kanze

A template with fewer arguments is considered more specialised than one
with more arguments, I guess. The more arguments a template has, the
more generic it is.

I think that the original poster was expecting the partial
ordering of function templates, described in §14.5.6.2 to enter
into play. I'll admit that I have great difficulty in
understanding this myself, but roughly speaking, I think the
idea is that the one function template is more specialized than
another if all of its specializations could also be valid
specializations of the other. Thus, for example, in:

template< typename T > void f( T ) ;
template< typename T > void f( T* ) ;

the second is more specialized, because all possible
specializations of it could also be specializations of the
first, where as the reverse is not true.

If this is really an accurate description, his functions
obviously aren't ordered, since it is trivial to find
specializations of one which can't possibly be a specialization
of the other, e.g.: foo( int, int ) can only specialize the
first, and foo( int*, double* ) can only specialize the second.

*IF* I understand it correctly (and as I say, this is so abtuse
that I'm far from sure), the partial ordering is present over
the function templates themselves, independantly of any
particular attempts to specialize.
Those are just guesses, of course. I don't have time to look through
the Standard for confirmation.

I think at a higher level, you've given the best possible
answer. If even better than average programmers have to study
the standard to figure out what is going on, then your code is
too complex, and you should avoid such constructs.
 
C

Craig Scott

template<typename T>
void foo(T,T){}

template<typename T1,typename T2>
void foo(T1*,T2*){}

int main( ) {

foo((int*)0,(int*)0);

}

Could anyone please explain me why the second template is not more
viable for overload resolution?
AFAIK each argument is matched with corresponding parameter. in that
case shouldnt T1* and T2* match better than T for (int*)? I assume T1
and T2 are disjoint aren't they? or must they be different types?

As far as the compiler is concerned, both can be matched equally well.
No conversions are involved in either case, so there is no reason for
the compiler to favour one over the other. You might be getting
confused with *class* partial specialization. Eg
#include <iostream>

template<typename T>
class Bar
{
public:
Bar() { std::cout << "(1)" << std::endl; }
};

template<typename T>
class Bar<T*>
{
public:
Bar() { std::cout << "(2)" << std::endl; }
};

int main()
{
Bar<int> barInt; // Prints (1)
Bar<int*> barIntPtr; // Prints (2)
}
 
J

James Kanze

As far as the compiler is concerned, both can be matched equally well.

In this case. If the choice were between:
template< typename T >
void foo( T, T ) ;
and
template< typename T >
void foo( T*, T* ) ;
however, there is a partial ordering of template
"specializations" which comes into play: basically, given two
function templates, if any time type deduction works for the
first, it works for the second, but there are cases where type
deduction can work for the second, but not for the first, then
the first is said to be "more specialized" than the second.
(Note that the use of "specialized" here has nothing to do with
template specialization.)
No conversions are involved in either case, so there is no
reason for the compiler to favour one over the other.

There isn't in this particular case, but there might be in other
cases. There is a partial ordering among function templates,
and that ordering does play a role in overload resolution.
 
C

Craig Scott

As far as the compiler is concerned, both can be matched equally well.
No conversions are involved in either case, so there is no reason for
the compiler to favour one over the other.

Sorry to reply to my own post, but after reading some of the other
replies on comp.lang.c++ I thought it worth adding some more info. The
partial ordering rules for function templates are given in section
14.5.5.2 of the C++ standard. In particular:

14.5.5.2/4: "... The transformed template is at least as specialized
as the other if, and only if, the deduction succeeds
and the deduced parameter types are an exact match (so the deduction
does not rely on implicit conversions)."

14.5.5.2/5: "A template is more specialized than another if, and only
if, it is at least as specialized as the other template
and that template is not at least as specialized as the first."

So in the case presented by the original post, since there are no
implicit conversions needed for either function, neither is considered
more specialized than the other and the overload is ambiguous.

HTH
 
J

James Kanze

Sorry to reply to my own post, but after reading some of the other
replies on comp.lang.c++ I thought it worth adding some more info. The
partial ordering rules for function templates are given in section
14.5.5.2 of the C++ standard. In particular:
14.5.5.2/4: "... The transformed template is at least as specialized
as the other if, and only if, the deduction succeeds
and the deduced parameter types are an exact match (so the deduction
does not rely on implicit conversions)."
14.5.5.2/5: "A template is more specialized than another if, and only
if, it is at least as specialized as the other template
and that template is not at least as specialized as the first."

You're quoting out of context. '14.5.5.2 is incredibly
difficult to understand, but one thing is clear: it establishes
a partial ordering over the function templates themselves,
independantly of the actual instantiations.
So in the case presented by the original post, since there are no
implicit conversions needed for either function, neither is considered
more specialized than the other and the overload is ambiguous.

Whether implicit conversions are needed or not for a specific
call has nothing to do with the ordering between the function
templates. In fact, the ordering between the function templates
is only considered if overload resolution would otherwise be
ambiguous. I'm reading '14.5.5.2 for the third time now in this
thread, and I'm gradually starting to understand what it is
saying. Basically, for each function template, the compiler
generates a unique imaginary argument for each template
parameter, and considers the resulting instantiation. If type
deduction for another function template succeeds with this
instance, then the function template in question is at least as
specialized as the function template for which type deduction
succeeded. This is an ordering relationship, which could be
symbolized by <=; i.e. for function templates x, y, x <= y IFF x
is at least as specialized as y. (Note that this ordering can
be established between any two function templates, regardless of
name or parameters, but it is only used in overload resolution,
which only concerns function templates with the same name.) In
overload resolution, if the call is otherwise ambiguous, and x
<= y, but !( y <= x ) (i.e. x < y), then overload resolution
chooses x.

The ordering is partial, and in this case, we have neither foo/1
<= foo/2 nor foo/2 <= foo/1. If the compiler instantiates foo/1
with some arbitrary, imaginary, non pointer type, type deduction
fails for foo/2, and if the compiler instantiates foo/2 with two
different imaginary T1 and T2, type deduction fails for foo/1.
So the two foo are unordered.

Note how this is different from:

template<typename T>
void foo(T,T){}

template<typename T>
void foo(T*,T*){}

int main( ) {
foo((int*)0,(int*)0);
}

In this case, too, both foo are "exact match" once type
deduction has occured. But in this case, foo/2 is unambiguously
more specialized than foo/1; if foo/2 is instantiated with some
imaginary type T, type deduction works for foo/1, but if foo/1
is instantiated with some imaginary (non-pointer) type T,
type deduction fails for foo/2.

Again, this ordering is over the function templates themselves,
independant of any instantiations.

(I'm sorry if I'm over explaining things here, but trying to
explain it in such detail is helping me to understand it.)
 
H

Hendrik Schober

James Kanze said:
[...]

In this case. If the choice were between:
template< typename T >
void foo( T, T ) ;
and
template< typename T >
void foo( T*, T* ) ;
however, there is a partial ordering of template
"specializations" which comes into play [...]

Does it? Are these template specializations?
I thought they are overloaded function
templates.

Schobi

--
(e-mail address removed) is never read
I'm HSchober at gmx dot de
"If there were some arcane way to remove the heads of every
newsgroup troll on the planet, I think it would elevate
humans to a whole new level of intelligence."
Rocky Frisco



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
H

hurcan solter

In this case. If the choice were between:
template< typename T >
void foo( T, T ) ;
and
template< typename T >
void foo( T*, T* ) ;
however, there is a partial ordering of template
"specializations" which comes into play [...]

Does it? Are these template specializations?
I thought they are overloaded function
templates.

Schobi

--
well they are not "specializations" per se but one is more
"specialized" than the other as the word is used by standard.
Same situation applies for the template specializations anyway,For
example;

template<typename T1,typename T2>
class Foo{};

template<typename T>
class Foo<T,T>{};

template<typename T1,typename T2>
class Foo<T1*,T2*>{};


int main()
{
Foo<int*,int*> zz;

}
Here, the instantiation is ambiguous again.the same resolution rules
apply .

@kanze
Thanks very much for your attempts at explaining the situation,and
your hint at formal ordering helped me found an excellent treatise of
the subject in Mr.Vandevoorde's book in section 12.2 which explains
why there is no ordering between the two templates that cleared it up
for me. I think i was stuck at the idea that the argument and
parameter pairs compared against their corresponding pairs in the
parameter list entirely , but the truth,as it is always, ia different
than what I've thought..
 
J

James Kanze

James Kanze said:
template<typename T>
void foo(T,T){}
template<typename T1,typename T2>
void foo(T1*,T2*){}
int main( ) {
foo((int*)0,(int*)0);
}
[...]
In this case. If the choice were between:
template< typename T >
void foo( T, T ) ;
and
template< typename T >
void foo( T*, T* ) ;
however, there is a partial ordering of template
"specializations" which comes into play [...]
Does it? Are these template specializations?
I thought they are overloaded function
templates.

That is extremely poorly expressed on my part. The partial
ordering is over the function templates themselves, not over
their specializations. Basically, here, after type deduction,
we have two functions which are exact matches. Both are
specializations of function templates, so the compiler attempts
to use this partial ordering to resolve the overloading. In
this case, it fails, because there is no ordering between these
two function templates, but in principal, when there is ordering
between the two function templates (not the specializations),
then the "more specialized" is chosen.
 
J

Jerry Coffin

given the code snippet;

template<typename T>
void foo(T,T){}

template<typename T1,typename T2>
void foo(T1*,T2*){}

int main( ) {

foo((int*)0,(int*)0);

}

Could anyone please explain me why the second template is not more
viable for overload resolution?

$14.5.5.2/3:
For each type template parameter, synthesize a unique type
and substitute that for each occurrence of that parameter
in the function parameter list, or for a template
conversion function, in the return type.

So, in the first case, T becomes "int *". In the second case, T1 and T2
both become "int". The result is two candidate functions, each of which
takes two parameters, both of type "int *".

$14.5.5.2/4, 5:
Using the transformed function parameter list, perform
argument deduction against the other function template.
The transformed template is at least as specialized as
the other if, and only if, the deduction succeeds and
the deduced parameter types are an exact match (so the
deduction does not rely on implicit conversions).

A template is more specialized than another if, and only
if, it is at least as specialized as the other template
and that template is not at least as specialized as the
first.

The parameters you're passing are an exact match for the tranformed
parameter lists of both functions. Neither template is more specialized
than the other so the call is ambiguous.

--
Later,
Jerry.

The universe is a figment of its own imagination.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
G

Greg Herlihy

$14.5.5.2/3:
For each type template parameter, synthesize a unique type
and substitute that for each occurrence of that parameter
in the function parameter list, or for a template
conversion function, in the return type.

So, in the first case, T becomes "int *". In the second case, T1 and T2
both become "int". The result is two candidate functions, each of which
takes two parameters, both of type "int *".

No, the paragraph cited from the Standard is describing how two, overloaded
function templates may be "partially-ordered" in relation to one another.
And since a partial ordering describes a relationship strictly between the
function templates themselves - a partial ordering never varies. Therefore
the types of arguments passed in the function call requiring overload
resolution - is irrelevant to the process of determining whether a partial
ordering exists between a pair of function templates. In other words, it is
possible to determine whether any two, overloaded function templates are
partially ordered in relation to each other - simply by performing the
comparison described by the Standard.

Furthermore, since the paragraph instructs us to "synthesize" a type - we
are free to come up with any type that we like. And because we are looking
for a type (or set of types) that will be a match for one foo() but not the
other, choosing "int *" as our synthesized type - is not a very good choice.
foo( int *, int *) is a match for either foo function template - so int * is
not the kind of synthesized type that we should be looking for.

Now, if we synthesize an "int" type instead - we are in business. Because a
foo with two int parameters like so:

foo( int, int )

is a match for:

foo( T, T )

but not a match for:

foo( T1 *, T2 * )

- because an "int" (of course) is not any kind of pointer type.

So at this point it appears that the foo( T1*, T2*) is the more specialized
function template - unless we can synthesize type arguments that would match
in the opposite manner. Can we do so? As it turns out, yes, we can. We can
synthesize a foo with two different pointer types as parameters - like so:

foo( int *, long *)

is a match for;

foo( T1 *, T2 *)

but not match a match for:

foo( T, T )

Because, of course, int * and long * are not the same type.

Therefore, since we were able to come up with one set of type arguments that
matched only one of the foo template functions but not the other ( and found
another set of types with the opposite matching behavior), we conclude that
neither foo function template is more specialized than the other. So with no
partial ordering to select one foo over the the other - the call is
ambiguous.

It is also worth point out - as James did earlier - that if foo( T, T ) were
replaced with foo( T1, T2 ) - then a partial ordering would exist between
the two foo() function templates.

Greg
 

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,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top