A function name doesn't represent the function; it is the overload set of the function name.
Your function
void foo(auto const &){}
appears to be using a concepts-esque extension of the language for a terse template function. In standard C++ it would read:
template<class T>
void foo(T const &){}
A template function isn't a function. It is an overload set of functions generated by that template.
An overload set of a function name is not a C++ object. And the things you can pass to functions are C++ objects.
Now, when the overload set of a function name only names one function, the compiler automatically resolves the overload and gives you that function object.
When the overload set of a function name is converted to a pointer-to-function with a fixed signature, overload resolution kicks in and (hopefully) one is selected.
When calling for_each
, however, the argument is not a specific fixed signature function pointer. Instead it is a generic type parameter. The compiler, at that point, has no way to resolve the overload set of the function name. It is ambiguous which one you want.
There are two solutions. One of them is to cast your function overload set into a specific function pointer. This requires you are explicit.
A second one is top wrap your overload set into a single object. You can do this with a manual function object with a template operator()
, or in C++14 you can do this:
#define OVERLOADS_OF(...) \
[](auto&&...args) \
noexcept(noexcept(__VA_ARGS__(decltype(args)(args)...))) \
->decltype( __VA_ARGS__(decltype(args)(args)...) ) \
{ return __VA_ARGS__(decltype(args)(args)...); }
which builds a stateless lambda representing the overloads of a global function name.
So:
void foo(auto const &){}
auto const rng{ranges::view::all(v)};
ranges::for_each(rng, OVERLOADS_OF(foo));
if you want to catch fewer corner cases, a simple:
void foo(auto const &){}
auto const rng{ranges::view::all(v)};
ranges::for_each(rng, [](auto&x){foo(x);});
also works in this specific case.
As an aside, there was a C++20 proposal to replace OVERLOADS_OF(foo)
with [](auto&&...args)=>foo(decltype(args)(args)...)
(generating the same effect as the macro would). Sadly, the decltype
and noexcept
features where voted down.