175

I want to pass an overloaded function to the std::for_each() algorithm. For example,

class A {
    void f(char c);
    void f(int i);

    void scan(const std::string& s) {
        std::for_each(s.begin(), s.end(), f);
    }
};

I'd expect the compiler to resolve f() by the iterator type. Apparently, it (GCC 4.1.2) doesn't do it. So, how can I specify which f() I want?

1

5 Answers 5

169

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.

Sign up to request clarification or add additional context in comments.

10 Comments

@the_drow: The second method is actually much safer, if one of the overloads goes away the first method silently gives undefined behavior, while the second catches the problem at compile time.
@BenVoigt Hmm, I tested this on vs2010 and couldn't find a case where the static_cast wouldn't catch the problem at compile time. It gave a C2440 with "None of the functions with this name in scope match the target type". Can you clarify?
@Nathan: It's possible I was thinking of reinterpret_cast. Most often I see C-style casts used for this. My rule is just that casts on function pointers are dangerous and unnecessary (as the second code snippet shows, an implicit conversion exists).
For member functions: std::for_each(s.begin(), s.end(), static_cast<void (A::*)(char)>(&A::f));
@sjwarner std::for_each won't accept pointer to member function.
|
43

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);
}

4 Comments

Hurray for lambdas! Indeed, an excellent solution to the overload resolution problem. (I thought of this also, but decided to leave it out of my answer so as not to muddy the waters.)
More code for the same result. I think that's not what the lambdas were made for.
@TomášZato The difference is that this answer works, and the accepted one doesn't (for the example posted by OP - you also need to use mem_fn and bind, which, BTW. are also C++11). Also, if we want to get really pedantic [&](char a){ return f(a); } is 28 characters, and static_cast<void (A::*)(char)>(&f) is 35 characters.
@TomášZato There you go coliru.stacked-crooked.com/a/1faad53c4de6c233 not sure how to make this more clear
30

Why doesn't it work

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 fs 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.

Generic solution to fixing it

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.

4 Comments

Since it took me a second, for member functions you can use std::mem_fn.
@Kostas No, you can't use std::mem_fn if the member function is overloaded (which is what the question is asking for).
Thank you for the response. Could you please help illustrate if this is at all possible with a method, which also has a private overload?
Nice explanation. What an absolutely byzantine incantation AS_LAMBDA() is... I think we wouldn't need it if, instead of having a freewheeling UnaryFunc template type for for_each()'s callback function, the language designers had simply constrained its callback type to be a function that takes one std::iterator_traits<I>::value_type (and returns some arbitrary type), where I is the iterator template type. Then deduction would Just Work, and if for some reason you actually wanted to call, say, the int overload of f() on a container of chars, you could just wrap it in a lambda.
6

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" );
}

Comments

6

If you don't mind using C++11, here's a clever helper that is similar to (but less ugly than) the static cast:

template<class... Args, class T, class R>
auto resolve(R (T::*m)(Args...)) -> decltype(m)
{ return m; }

template<class T, class R>
auto resolve(R (T::*m)(void)) -> decltype(m)
{ return m; }

(Works for member functions; should be obvious how to modify it to work for freestanding functions, and you should be able to provide both versions and the compiler will select the right one for you.)

With thanks to Miro Knejp for suggesting: see also https://groups.google.com/a/isocpp.org/d/msg/std-discussion/rLVGeGUXsK0/IGj9dKmSyx4J.

5 Comments

OP's problem is not being able to pass an overloaded name into a function template, and your solution involves passing an overloaded name into a function template? This is just exactly the same problem.
@Barry Not the same problem. Template argument deduction succeeds in this case. It works (with a few minor tweaks).
@Oktalist Because you're providing R, it's not deduced. There's also no mention of that in this answer.
@Barry I'm not providing R, I'm providing Args. R and T are deduced. It's true the answer could be improved. (There is no T in my example though, because it's not a pointer-to-member, because that wouldn't work with std::for_each.)
I upvoted this earlier. It's a nice approach, however I now discover it doesn't generalize. E.g., resolve<> won't resolve a zero-argument function, and so on. (For an approach that does work, check out pybind11's overload_cast.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.