We declare the function pointer, i.e., void (*ptr)(char*). The statement ptr=printname means that we are assigning the address of printname() function to ptr. Now, we can call the printname() function by using the statement ptr(s).
Answer. A call to an overloaded function can be ambiguous in one of the following two ways: *The arguments mentioned in the function where it is called do not match the arguments at the point where the function is called. *The same function is defined more than one time in the same program.......
You overload a function name f by declaring more than one function with the name f in the same scope. The declarations of f must differ from each other by the types and/or the number of arguments in the argument list.
You can use static_cast<>()
to specify which f
to use according to the function signature implied by the function pointer type:
// Uses the void f(char c); overload
std::for_each(s.begin(), s.end(), static_cast<void (*)(char)>(&f));
// Uses the void f(int i); overload
std::for_each(s.begin(), s.end(), static_cast<void (*)(int)>(&f));
Or, you can also do this:
// The compiler will figure out which f to use according to
// the function pointer declaration.
void (*fpc)(char) = &f;
std::for_each(s.begin(), s.end(), fpc); // Uses the void f(char c); overload
void (*fpi)(int) = &f;
std::for_each(s.begin(), s.end(), fpi); // Uses the void f(int i); overload
If f
is a member function, then you need to use mem_fun
, or for your case, use the solution presented in this Dr. Dobb's article.
Lambdas to the rescue! (note: C++11 required)
std::for_each(s.begin(), s.end(), [&](char a){ return f(a); });
Or using decltype for the lambda parameter:
std::for_each(s.begin(), s.end(), [&](decltype(*s.begin()) a){ return f(a); });
With polymorphic lambdas (C++14):
std::for_each(s.begin(), s.end(), [&](auto a){ return f(a); });
Or disambiguate by removing overloading (only works for free functions):
void f_c(char i)
{
return f(i);
}
void scan(const std::string& s)
{
std::for_each(s.begin(), s.end(), f_c);
}
I'd expect the compiler to resolve
f()
by the iterator type. Apparently, it (gcc 4.1.2) doesn't do it.
It'd be great if that were the case! However, for_each
is a function template, declared as:
template <class InputIterator, class UnaryFunction>
UnaryFunction for_each(InputIterator, InputIterator, UnaryFunction );
Template deduction needs to select a type for UnaryFunction
at the point of the call. But f
doesn't have a specific type - it's an overloaded function, there are many f
s each with different types. There is no current way for for_each
to aid the template deduction process by stating which f
it wants, so template deduction simply fails. In order to have the template deduction succeed, you need to do more work on the call site.
Hopping in here a few years and C++14 later. Rather than use a static_cast
(which would allow template deduction to succeed by "fixing" which f
we want to use, but requires you to manually do overload resolution to "fix" the correct one), we want to make the compiler work for us. We want to call f
on some args. In the most generic way possible, that's:
[&](auto&&... args) -> decltype(auto) { return f(std::forward<decltype(args)>(args)...); }
That's a lot to type, but this sort of problem comes up annoyingly frequently, so we can just wrap that in a macro (sigh):
#define AS_LAMBDA(func) [&](auto&&... args) -> decltype(func(std::forward<decltype(args)>(args)...)) { return func(std::forward<decltype(args)>(args)...); }
and then just use it:
void scan(const std::string& s) {
std::for_each(s.begin(), s.end(), AS_LAMBDA(f));
}
This will do exactly what you wish the compiler did - perform overload resolution on the name f
itself and just do the right thing. This will work regardless of whether f
is a free function or a member function.
Not to answer your question, but am I the only one that finds
for ( int i = 0; i < s.size(); i++ ) {
f( s[i] );
}
both simpler and shorter than the for_each
alternative suggested by in silico in this case?
The problem here seems to be not overload resolution but in fact template parameter deduction. While the excellent answer from @In silico will solve an ambiguous overloading problem in general, it seems the best fix when dealing with std::for_each
(or similar) is to explicitly specify its template parameters:
// Simplified to use free functions instead of class members.
#include <algorithm>
#include <iostream>
#include <string>
void f( char c )
{
std::cout << c << std::endl;
}
void f( int i )
{
std::cout << i << std::endl;
}
void scan( std::string const& s )
{
// The problem:
// error C2914: 'std::for_each' : cannot deduce template argument as function argument is ambiguous
// std::for_each( s.begin(), s.end(), f );
// Excellent solution from @In silico (see other answer):
// Declare a pointer of the desired type; overload resolution occurs at time of assignment
void (*fpc)(char) = f;
std::for_each( s.begin(), s.end(), fpc );
void (*fpi)(int) = f;
std::for_each( s.begin(), s.end(), fpi );
// Explicit specification (first attempt):
// Specify template parameters to std::for_each
std::for_each< std::string::const_iterator, void(*)(char) >( s.begin(), s.end(), f );
std::for_each< std::string::const_iterator, void(*)(int) >( s.begin(), s.end(), f );
// Explicit specification (improved):
// Let the first template parameter be derived; specify only the function type
std::for_each< decltype( s.begin() ), void(*)(char) >( s.begin(), s.end(), f );
std::for_each< decltype( s.begin() ), void(*)(int) >( s.begin(), s.end(), f );
}
void main()
{
scan( "Test" );
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With