#include <thread>
#include <functional>
#include <utility>
using namespace std;
template<typename Callable, typename... Args>
void Async(Callable&& fn, Args&&... args)
{
    auto fn_wrapper = [](Callable&& fn, Args&&... args)
    {
        invoke(forward<Callable>(fn), forward<Args>(args)...);
    };
    // ok
    fn_wrapper(forward<Callable>(fn), forward<Args>(args)...);
    // ok
    async(forward<Callable>(fn), forward<Args>(args)...);
    // error : no matching function for call to 'async'
    async(fn_wrapper, forward<Callable>(fn), forward<Args>(args)...);
}
void f(int, int) {}
int main()
{
    Async(f, 1, 2);
    this_thread::sleep_for(1min);
}
The following code is ok:
fn_wrapper(forward<Callable>(fn), forward<Args>(args)...);
The following code is also ok:
async(forward<Callable>(fn), forward<Args>(args)...);
However, the following code is NOT ok:
// error : no matching function for call to 'async' async(fn_wrapper, forward<Callable>(fn), forward<Args>(args)...);
The last case fails to compile with the following error:
main.cpp:27:5: fatal error: no matching function for call to 'async'
    async(fn_wrapper,
    ^~~~~
main.cpp:36:5: note: in instantiation of function template specialization 'Async<void (&)(int, int), int, int>' requested here
    Async(f, 1, 2);
    ^
  [...]
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/6.3.0/../../../../include/c++/6.3.0/future:1739:5: note: candidate template ignored: substitution failure [with _Fn = (lambda at main.cpp:12:9) &, _Args = <void (&)(int, int), int, int>]: no type named 'type' in 'std::result_of<(lambda at main.cpp:12:9) (void (*)(int, int), int, int)>'
    async(_Fn&& __fn, _Args&&... __args)
Why does the last case not work?
Perfect forwarding (&&) works only in template argument context. But your lambda is not a template. So (Callable&& fn, Args&&... args) just slaps && onto every argument and actually means "pass by rvalue reference", which isn't going to perfect-forward properly.
But more importantly, std::async calls the functor as INVOKE(DECAY(std::forward<F>(f)), DECAY(std::forward<Args>(args))...), so the deduced functor's parameter types are actually decayed Callable and Args.
Try this wrapper instead:
    auto fn_wrapper = [](auto&& fn, auto&&... args)
    {
        invoke(forward<decltype(fn)>(fn), forward<decltype(args)>(args)...);
    };
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With