The issue is that it can't be done with function pointers alone, since you want to resolve the function overload when it's bound to the argument. You can't get a function pointer to function without performing overload resolution. The key is to provide a function object that performs the overload on call, as opposed to trying to get a function pointer at the start.
For this, I would declare the primary function as
template<typename Func, typename ...B> auto
map(Func&& f, std::tuple<B...> &&t)
-> decltype(map_1(std::forward<Func>(f), std::forward<std::tuple<B...>>(t), typename gens<sizeof...(B)>::type()))
{
return map_1(std::forward<Func>(f), std::forward<std::tuple<B...>>(t), typename gens<sizeof...(B)>::type());
}
And then defined map_1
in a similar fashion.
Then you can make a function object wrapper
struct Wrapper
{
template<typename T>
auto operator()(T&& t) const -> decltype( f(std::forward<T>(t)) )
{
return f(std::forward<T>(t));
}
};
and call it with map(Wrapper(), make_tuple(3.14, "a string"))
Edit: if you have C++14, you can do the following (thanks @MooingDuck for inspiration)
#define BINDOVERLOADED(X) [](auto&& t) { return X(std::forward<decltype(t)>(t)); }
auto x = map(BINDOVERLOADED(f), make_tuple(3.14, "a string"));