tags:

views:

121

answers:

3

Trivial code that works if I do not overload myfunc.

void myfunc(int i)
{
    std::cout << "calling myfunc with arg " << i << std::endl;
}
void myfunc(std::string s)
{
    std::cout << "calling myfunc with arg " << s << std::endl;
}
void testalgos()
{
    std::vector<int> v;
    v.push_back(1);
    v.push_back(2);

    std::vector<std::string> s;
    s.push_back("one");
    s.push_back("two");

    std::for_each( v.begin(), v.end(), myfunc);
    std::for_each( s.begin(), s.end(), myfunc);
    return;
}

int _tmain(int argc, _TCHAR* argv[])
{
    std::cout << "Hello World" << std::endl;
    testalgos();
    return 0;
}

The following build errors repeat for both for_each calls.

error C2914: 'std::for_each' : cannot deduce template argument as function argument is ambiguous error C2784: '_Fn1 std::for_each(_InIt,_InIt,_Fn1)' : could not deduce template argument for '_InIt' from 'std::_Vector_iterator<_Ty,_Alloc>'.

It does work if I do not overload myfunc.Can someone explain what is happening here.

TIA

+7  A: 

In that context the overloads can't be resolved by the compiler. std::for_each() expects some arbitrary type F for its functor, not some specific function type, thus the overloaded myFunc is ambiguous here.

You can explicitly select which overload to use:

std::for_each( v.begin(), v.end(), (void (*)(int))myfunc);
std::for_each( s.begin(), s.end(), (void (*)(std::string))myfunc);

Alternatives (last two are from the comments):

typedef void (*IntFunc)(int);
std::for_each(/*...*/, (IntFunc)myfunc);

typedef void IntFunc(int);
std::for_each(/*...*/, static_cast<IntFunc*>(&myFunc));

// using identity (e.g. from boost or C++0x):
std::for_each(/*...*/, (identity<void(int)>::type*)myfunc);
Georg Fritzsche
Thanks. So, the compiler really is unable to resolve and we need to add "hints". Just curious, do I need this in all STL or template related code?
Sidjal
It depends on the template functions you call - you wouldn't need it if the overload can be resolved, e.g. `template<class T> void f(T, void (*)(T))` would work fine with `f(someInt, myFunc)`. The STL mostly uses completely unrestrained types for function parameters however and needs *"hints"*.
Georg Fritzsche
The typedefs also work without parens, with explicitly writing `*`, and C++-style casts: `typedef void IntFunc(int); std::for_each( ..., static_cast<IntFunc *>( `
Potatoswatter
... or when using identitiy `std::for_each(..., (identity<void(int)>::type*)myfunc);` :)
Johannes Schaub - litb
+3  A: 

Compiler cannot deduce type of functor. You could make your function template:

template<typename T> void myfunc(T);

template<> void myfunc(int i)
{
    std::cout << "calling myfunc with arg " << i << std::endl;
}
template<> void myfunc(std::string s)
{
    std::cout << "calling myfunc with arg " << s << std::endl;
}

Then use it as follows:

std::for_each( v.begin(), v.end(), myfunc<int>);
std::for_each( s.begin(), s.end(), myfunc<std::string>);
Kirill V. Lyadvinsky
I think I was looking for something like this. Thanks. Back to my tutorials.
Sidjal
Most people expect pure overloading if templates aren't required. See http://www.gotw.ca/publications/mill17.htm for caveats.
Potatoswatter
+1  A: 

The compiler cannot deduce which to use, as both overloads would match the argument (which doesn't depend on the types of the iterator in any way) equally well.

Another option in addition to explicitly casting the argument to suitable pointer type might be here to use the std::ptr_fun helper function to wrap it in a functor, and help the template deduction by giving (part of) it explicitly.

std::for_each( v.begin(), v.end(), std::ptr_fun<int>(myfunc));
std::for_each( s.begin(), s.end(), std::ptr_fun<std::string>(myfunc));
UncleBens