You can do what you want, as this simple program shows:
template <class ... Ts> void foo(std::function<void(Ts...)> f, Ts && ... ts) { f(std::forward<Ts>(ts)...); } int main() { std::function<void(int)> f = [] (int i) { std::cerr << "hello " << i; }; foo(f, 5); return 0; }
The thing is, that once RunSafeFn2 is a template, you may as well also template the functor itself. There's very little benefit to type erasing the callable when you are already a template. So in practice, it just makes more sense to do:
template <class F, class ... Ts> void foo(F f, Ts && ... ts) { f(std::forward<Ts>(ts)...); }
Which still allows the usage above, but also allows doing:
foo([] (int i) { std::cerr << "hello " << i; }, 5);
Which will also be more efficient since you completely avoid creating a std::function object. To handle the return type, since you're limited to C++11, you could do:
template <class F, class ... Ts> auto foo(F f, Ts && ... ts) -> boost::variant<decltype(f(std::forward<Ts>(ts)...)), std::string> { try { return f(std::forward<Ts>(ts)...); } ... }
Edit: let me add one final thought: In C++11 and on, where callables are so easy to create, a much simpler alternative to this is actually to take a callable and no arguments:
template <class F> auto foo(F f) -> boost::variant<decltype(f()), std::string> { try { return f(); } ... }
That's because it's pretty easy to capture around the arguments that you need. For example, if I had written my original example that way, I could use it by doing:
int i = 5; foo([&] () { std::cerr << "hello " << i; });
This has pros and cons especially perhaps when dealing with move only types, but if you want to minimize maintenance burden and your use cases are simple, this is a reasonable alternative.
error: declaration type contains unexpanded parameter pack 'Ts'with squiggles under theTsinfunction<U(Ts)>. If I were to judge, I'd say that's fairly clear.