Overload resolution of function templates

  • Thread starter matthias.neubauer
  • Start date

M

matthias.neubauer

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
 
Ad

Advertisements

M

mojumbo

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
 
R

Rolf Magnus

mojumbo said:
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.
 
V

Vidar Hasfjord

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
 
M

matthias.neubauer

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!
 
J

Jiøí Paleèek

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
 
Ad

Advertisements

M

matthias.neubauer

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
 
Ad

Advertisements

T

Triple-DES

  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.
 

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

Top