c++std-functionpackaged-task

Can a member function be used anywhere a free function can using std::function?


I have some code (courtesy of progschj on GitHub) which I have adapted to exemplify my question. MakeTask moves any function and its arguments into MakeTask which makes a packaged_task. The created task is executed whereupon its future is returned to the caller. This is very slick, but I would like to be able to do this with a member function as well. But if I put Func into a struct, F&& in MakeTask fails with the errors noted in the code.

#include <future>
#include <memory>
#include <string>
#include <functional>

template<class F, class... Args>
auto MakeTask( F&& f, Args&&... args )-> std::future< typename std::result_of< F( Args... ) >::type >
{
  typedef typename std::result_of< F( Args... ) >::type return_type;

  auto task = std::make_shared< std::packaged_task< return_type() > >(
    std::bind( std::forward< F >( f ), std::forward< Args >( args )... )
    );

  std::future< return_type > resultFuture = task->get_future();

  ( *task )( );

  return resultFuture;
}

struct A
{
  int Func( int nn, std::string str )
  {
    return str.length();
  }
};

int main()
{
  // error C2893: Failed to specialize function template 'std::future<std::result_of<_Fty(_Args...)>::type> MakeTask(F &&,Args &&...)'
  // note: 'F=int (__thiscall A::* )(int,std::string)'
  // note: 'Args={int, const char (&)[4]}'
  auto resultFuture = MakeTask( &A::Func, 33, "bbb" );  // does not compile

  int nn = resultFuture.get();

  return 0;
}

I can make it work if I turn Func into a static, but that will break other parts of my app code.

Edit1: I figured out the syntax for std::function and modified the sample with the new error messages. MakeTask’s F&& move argument doesn’t accept my aFunc as a callable object.

Edit2: Because of Barry's answer, I change the sample code back to the original posting so his answer makes sense to future viewers.


Solution

  • &A::Func is a non-static member function, which means that it needs an instance of A to operate in. The convention that all the function objects/adapters use is that the 1st argument provided will be that instance.

    MakeTask() requires that the first argument (F) be invoke-able with all the other arguments (Args...). &A::Func requires three arguments: an object of type A (or pointer to A or reference_wrapper<A>), an int, and a string. You're simply missing the first one:

    auto resultFuture = MakeTask( &A::Func, A{}, 33, "bbb" );
                                           ^^^^^