[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

Overload resolution of function templates

matthias.neubauer

10/3/2008 2:08:00 PM

I have problems understanding how overloading of function templates
works.

Consider first the following code without any function templates ...

int foo(const char *& c)
{
return 0;
}

int foo(const char *c)
{
return 1;
}

int main() {
const char * s = "Hi!";
return foo(s);
}

Overloading resolution of foo is ambiguous, as can be witness by e.g. g
++

Foo.cpp: In function 'int main()':
Foo.cpp:14: error: call of overloaded 'foo(const char*&)' is ambiguous
Foo.cpp:2: note: candidates are: int foo(const char*&)
Foo.cpp:7: note: int foo(const char*)

If I now use function templates for foo, foo_t, as follows

template<typename C>
int foo_t(C& c)
{
return 0;
}

template<typename C>
int foo_t(const C *c)
{
return 1;
}

int main() {
const char * s = "Hi!";
return foo_t(s);
}

some implementations I tested (g++, msvc) seem to find a best
candidate function for foo_i which I do not understand.

As I read 13.3.1 para 7 of the standard, I would expect an
implementation to first determine specializations for foo_t (here:
foo_t<const char *> and foo_t<char> resp.), and then proceed as above.
Hence, I'd also expect an ambiguity error here. Where is my
misunderstanding?

Cheers,

Matthias





7 Answers

mojumbo

10/3/2008 2:40:00 PM

0

On Oct 3, 10:07 am, matthias.neuba...@gmail.com wrote:
> I have problems understanding how overloading of function templates
> works.
>
> Consider first the following code without any function templates ...
>
> int foo(const char *& c)
> {
> return 0;
> }
>
> int foo(const char *c)
> {
> return 1;
> }
>
> int main() {
> const char * s = "Hi!";
> return foo(s);
> }
>
> template<typename C>
> int foo_t(C& c)
> {
> return 0;
> }
>
> template<typename C>
> int foo_t(const C *c)
> {
> return 1;
> }
>
> int main() {
> const char * s = "Hi!";
> return foo_t(s);
> }
>
> some implementations I tested (g++, msvc) seem to find a best
> candidate function for foo_i which I do not understand.
>
> As I read 13.3.1 para 7 of the standard, I would expect an
> implementation to first determine specializations for foo_t (here:
> foo_t<const char *> and foo_t<char> resp.), and then proceed as above.
> Hence, I'd also expect an ambiguity error here. Where is my
> misunderstanding?

The specializations are determined but now your function arguments
have changed. The two methods become:

int foot_t(const char*&)
and
int foo_t(const char**)

So if you're passing in a const char* my expectation would be the
foo_t(const char*&) method is called


Rolf Magnus

10/3/2008 3:35:00 PM

0

mojumbo wrote:

> On Oct 3, 10:07 am, matthias.neuba...@gmail.com wrote:
>> I have problems understanding how overloading of function templates
>> works.
>>
>> Consider first the following code without any function templates ...
>>
>> int foo(const char *& c)
>> {
>> return 0;
>> }
>>
>> int foo(const char *c)
>> {
>> return 1;
>> }
>>
>> int main() {
>> const char * s = "Hi!";
>> return foo(s);
>> }
>>
>> template<typename C>
>> int foo_t(C& c)
>> {
>> return 0;
>> }
>>
>> template<typename C>
>> int foo_t(const C *c)
>> {
>> return 1;
>> }
>>
>> int main() {
>> const char * s = "Hi!";
>> return foo_t(s);
>> }
>>
>> some implementations I tested (g++, msvc) seem to find a best
>> candidate function for foo_i which I do not understand.
>>
>> As I read 13.3.1 para 7 of the standard, I would expect an
>> implementation to first determine specializations for foo_t (here:
>> foo_t<const char *> and foo_t<char> resp.), and then proceed as above.
>> Hence, I'd also expect an ambiguity error here. Where is my
>> misunderstanding?
>
> The specializations are determined but now your function arguments
> have changed. The two methods become:
>
> int foot_t(const char*&)
> and
> int foo_t(const char**)

Why? foo_t(const char**) wouldn't fit, and it wouldn't even be a possible
template instance (what would the template argument C be?).
But foo_t(const char*) would fit (with C=char). And actually, my compiler is
choosing that one.

Vidar Hasfjord

10/3/2008 3:51:00 PM

0

On Oct 3, 3:07 pm, matthias.neuba...@gmail.com wrote:
> I have problems understanding how overloading of function templates
> works.
> [...]
> As I read 13.3.1 para 7 of the standard, I would expect an
> implementation to first determine specializations for foo_t (here:
> foo_t<const char *> and foo_t<char> resp.), and then proceed as above.
> Hence, I'd also expect an ambiguity error here. Where is my
> misunderstanding?

When function templates are involved then selection is based on which
candidate is more specialized. See "13.3.3 Best Viable Function" and
"14.5.6.2 Partial ordering of function templates" (Draft C++ Standard,
N2723).

For example,

template <class T> void foo (T a); // #1
template <class T> void foo (T* a); // #2, more specialized
int* a; foo (a); // selects #2

Regards,
Vidar Hasfjord

matthias.neubauer

10/3/2008 4:31:00 PM

0

On Oct 3, 5:50 pm, Vidar Hasfjord <vattilah-gro...@yahoo.co.uk> wrote:

> When function templates are involved then selection is based on which
> candidate is more specialized. See "13.3.3 Best Viable Function" and
> "14.5.6.2 Partial ordering of function templates" (Draft C++ Standard,
> N2723).

Ok, now I see. [over.match.best] compares function template
specializations differently. That's the part I was missing. Thanks!

Jirí Palecek

10/3/2008 5:43:00 PM

0

On Fri, 03 Oct 2008 16:07:46 +0200, <matthias.neubauer@gmail.com> wrote:

> I have problems understanding how overloading of function templates
> works.
>

.... snip ...

> If I now use function templates for foo, foo_t, as follows
>
> template<typename C>
> int foo_t(C& c)
> {
> return 0;
> }
>
> template<typename C>
> int foo_t(const C *c)
> {
> return 1;
> }
>
> int main() {
> const char * s = "Hi!";
> return foo_t(s);
> }
>
> some implementations I tested (g++, msvc) seem to find a best
> candidate function for foo_i which I do not understand.
>
> As I read 13.3.1 para 7 of the standard, I would expect an
> implementation to first determine specializations for foo_t (here:
> foo_t<const char *> and foo_t<char> resp.), and then proceed as above.
> Hence, I'd also expect an ambiguity error here. Where is my
> misunderstanding?

The reason why there is no ambiguity, is because the two functions are
ordered by the partial ordering of functions. That is, the second template
is more specialized than the first. That is possible because, when
matching (const C*) against C&, the reference is stripped from C& (see
14.8.2.1/2). If you call foo_t(1) [eg. calling the C& version with an
rvalue], overload resolution succeeds, but the call fails.

Regards
Jiri Palecek

matthias.neubauer

10/7/2008 10:45:00 AM

0

On Oct 3, 7:42 pm, Jirí Palecek <jpale...@web.de> wrote:
> On Fri, 03 Oct 2008 16:07:46 +0200, <matthias.neuba...@gmail.com> wrote:

> > template<typename C>
> > int foo_t(C& c)
> > {
> > return 0;
> > }
>
> > template<typename C>
> > int foo_t(const C *c)
> > {
> > return 1;
> > }
>
> > int main() {
> > const char * s = "Hi!";
> > return foo_t(s);
> > }

> The reason why there is no ambiguity, is because the two functions are
> ordered by the partial ordering of functions. That is, the second template
> is more specialized than the first. That is possible because, when
> matching (const C*) against C&, the reference is stripped from C& (see
> 14.8.2.1/2). If you call foo_t(1) [eg. calling the C& version with an
> rvalue], overload resolution succeeds, but the call fails.

ALright. I am still a little bit confused. As you say, when comparing
function templates ("14.5.5.2 partial ordering of function
templates"), we perform argument deduction. But 14.5.5.2p4 also
dictates

"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)."

What exactly does the term "exact match" mean in this context? Is this
specified somewhere else?

In my example above, as I understand it, the deduced parameter type
for (C&) is

const C*&

which is NOT an exact match to

const C*.

Instead, we MUST use an implicit conversion to strip away the
reference.

Or, does the term "exact match" mean here, we still compare the
deduced parameter type and the expected parameter type "inexactly" by
ignoring
some parts as specified in 14.8.2.1?

-Matthias

Triple-DES

10/7/2008 10:56:00 AM

0

On 7 Okt, 12:45, matthias.neuba...@gmail.com wrote:
> On Oct 3, 7:42 pm, Jiøí Paleèek <jpale...@web.de> wrote:
>
>
>
>
>
> > On Fri, 03 Oct 2008 16:07:46 +0200, <matthias.neuba...@gmail.com> wrote:
> > >   template<typename C>
> > >   int foo_t(C& c)
> > >   {
> > >    return 0;
> > >   }
>
> > >   template<typename C>
> > >   int foo_t(const C *c)
> > >   {
> > >    return 1;
> > >   }
>
> > >   int main() {
> > >     const char * s = "Hi!";
> > >     return foo_t(s);
> > >   }
> > The reason why there is no ambiguity, is because the two functions are
> > ordered by the partial ordering of functions. That is, the second template
> > is more specialized than the first. That is possible because, when
> > matching (const C*) against C&, the reference is stripped from C& (see
> > 14.8.2.1/2). If you call foo_t(1) [eg. calling the C& version with an
> > rvalue], overload resolution succeeds, but the call fails.
>
> ALright. I am still a little bit confused. As you say, when comparing
> function templates ("14.5.5.2 partial ordering of function
> templates"), we perform argument deduction. But 14.5.5.2p4 also
> dictates
>
>   "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)."
>
> What exactly does the term "exact match" mean in this context? Is this
> specified somewhere else?
>
> In my example above, as I understand it, the deduced parameter type
> for (C&) is
>
>    const C*&
>
> which is NOT an exact match to
>
>    const C*.
>
> Instead, we MUST use an implicit conversion to strip away the
> reference.
>
> Or, does the term "exact match" mean here, we still compare the
> deduced parameter type and the expected parameter type "inexactly" by
> ignoring
> some parts as specified in 14.8.2.1?
>
> -Matthias

Yes, there is a special case for reference binding, so that the
conversion from const C* to const C*& has "Exact Match" ranking.