Function overloading question


B

blaz.bratanic

#include <iostream>
#include <vector>
#include <list>

template <typename T>
void foo(T a) {
std::cout << "General" << std::endl;
}

template <typename T>
void foo(std::vector<T> a) {
std::cout << "Vector" << std::endl;
}

int main() {
std::vector<int> v = {1,2,3};
foo(v); // vector

std::list<int> l = {1,2,3};
foo(l); // general
}

Could someone explain does the call to foo not result in an ambiguous call?

Probably the question is, why the compiler prefers
foo<int> over foo<std::vector<int>>?

thanks
 
Ad

Advertisements

A

Alf P. Steinbach

#include <iostream>
#include <vector>
#include <list>

template <typename T>
void foo(T a) {
std::cout << "General" << std::endl;
}

template <typename T>
void foo(std::vector<T> a) {
std::cout << "Vector" << std::endl;
}

int main() {
std::vector<int> v = {1,2,3};
foo(v); // vector

std::list<int> l = {1,2,3};
foo(l); // general
}

Could someone explain [why] does the call to foo not result in an ambiguous call?

Because the formal argument types are sufficiently different, and the
one with std::vector<T> is more specialized.

I once knew a good part of the C++03 rules for this, but unless you
happen to have photographic memory and extremely high IQ, I recommend
just going by gut feeling, thinking about the goals of the rules rather
than the rules themselves. They're pretty complicated and spread around.
Perhaps there are some regulars here, or one, that has a very good grasp
of the current rules, but I doubt it: I think most C++ programmers
simply go by gut feeling and compiler's feedback. ;-)

Probably litb over at Stack Overflow knows the rules (he has that memory
and IQ and interest in the C++ standard), but if you ask a regular
question there you're likely to get some plausible but wrong answers --
what you can do instead is to visit the C++ lounge chat.

Probably the question is, why the compiler prefers
foo<int> over foo<std::vector<int>>?

Oh it doesn't.


Cheers & hth.,

- Alf
 
V

Victor Bazarov

#include <iostream>
#include <vector>
#include <list>

template <typename T>
void foo(T a) {
std::cout << "General" << std::endl;
}

template <typename T>
void foo(std::vector<T> a) {
std::cout << "Vector" << std::endl;
}

int main() {
std::vector<int> v = {1,2,3};
foo(v); // vector

std::list<int> l = {1,2,3};
foo(l); // general
}

Could someone explain does the call to foo not result in an ambiguous call?

Two function templates against which to check each call. Both templates
have the type deduction context from the standard ones, which means that
deduction is not going to fail. But even if it would fail, the failure
is not an error, and it would pick another template. Ambiguity exists
in overloading functions, not function templates, IIUIC.
Probably the question is, why the compiler prefers
foo<int> over foo<std::vector<int>>?

The rule is to prefer a more specialized version, IIRC. foo<int> is
more specialized (more limited) than foo<T> with T==std::vector<int>.
BTW, what output do you get?

V
 
B

blaz.bratanic

Two function templates against which to check each call. Both templates

have the type deduction context from the standard ones, which means that

deduction is not going to fail. But even if it would fail, the failure

is not an error, and it would pick another template. Ambiguity exists

in overloading functions, not function templates, IIUIC.








The rule is to prefer a more specialized version, IIRC. foo<int> is

more specialized (more limited) than foo<T> with T==std::vector<int>.

BTW, what output do you get?



V

Hmm, since this are two distinct templates I thought types for both are deduced
and functions added to a set of candidate functions. Thus the best candidate function is selected at overload resolution, or am I wrong?

The output is written in comments next to function calls:
std::vector<int> v = {1,2,3};
foo(v); // outputs "Vector" -- foo<int> is selected

std::list<int> l = {1,2,3};
foo(l); // outputs "General" -- foo<std::list<int>> is selected

b
 
A

Alf P. Steinbach

On 05.12.2013 15:28, (e-mail address removed) wrote:
[snip double-spaced quoting, please don't]
Hmm, since this are two distinct templates I thought types for both are deduced
and functions added to a set of candidate functions. Thus the best candidate function is selected at overload resolution, or am I wrong?

Except that if an ordinary function competes with a template
instantiation, the ordinary function wins. Which among other things
means that you can't directly overload so as to catch raw arrays with a
function template and pointers with an ordinary overload. One solution
is to be more explicit in the calls, another solution (now favored by
Scott Meyers) is to use a common function template that dispatches.

The output is written in comments next to function calls:
std::vector<int> v = {1,2,3};
foo(v); // outputs "Vector" -- foo<int> is selected

std::list<int> l = {1,2,3};
foo(l); // outputs "General" -- foo<std::list<int>> is selected

Right.


Cheers & hth.,

- Alf
 
A

Alf P. Steinbach

On 05.12.2013 15:28, (e-mail address removed) wrote:
[snip double-spaced quoting, please don't]
Hmm, since this are two distinct templates I thought types for both
are deduced
and functions added to a set of candidate functions. Thus the best
candidate function is selected at overload resolution, or am I wrong?

Except that if an ordinary function competes with a template
instantiation, the ordinary function wins. Which among other things
means that you can't directly overload so as to catch raw arrays with a
function template and pointers with an ordinary overload. One solution
is to be more explicit in the calls, another solution (now favored by
Scott Meyers) is to use a common function template that dispatches.

The output is written in comments next to function calls:
std::vector<int> v = {1,2,3};
foo(v); // outputs "Vector" -- foo<int> is selected

That's not `foo<int>`, that's `foo( std::vector<int> )`.

Oh sorry, you're right, it's foo<int> which is foo<int>( std::vector<int> ).


My mother just arrived from travels and used up 99% of my processing
ability.

Also I need some coffee... ;-)
 
Ad

Advertisements

B

bblaz

On 05.12.2013 15:28, (e-mail address removed) wrote:
[snip double-spaced quoting, please don't]
Hmm, since this are two distinct templates I thought types for both
are deduced
and functions added to a set of candidate functions. Thus the best
candidate function is selected at overload resolution, or am I wrong?

Except that if an ordinary function competes with a template
instantiation, the ordinary function wins. Which among other things
means that you can't directly overload so as to catch raw arrays with a
function template and pointers with an ordinary overload. One solution
is to be more explicit in the calls, another solution (now favored by
Scott Meyers) is to use a common function template that dispatches.

The output is written in comments next to function calls:
std::vector<int> v = {1,2,3};
foo(v); // outputs "Vector" -- foo<int> is selected

That's not `foo<int>`, that's `foo( std::vector<int> )`.

Oh sorry, you're right, it's foo<int> which is foo<int>(
std::vector<int> ).


My mother just arrived from travels and used up 99% of my processing
ability.

Also I need some coffee... ;-)
Right.


Cheers & hth.,

- Alf

I think i found the reason why it its so.

14.5.6.2 Partial ordering of function templates

thanks for all replies!

blaz
 

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