Search code examples
c++variadic-templatesstd-function

Wrap N-arg function into another function


I have a function which executes another function in worker thread:

void run_in_worker_thread( std::function< void( ) > proc )

Now I would like to implement function schedule() which takes proc() function as argument and returns function which executes proc() in worker thread via run_in_worker_thread().

Here is my implementation:

#include <iostream>
#include <functional>

using namespace std;

class Test
{
  public:
    void run_in_worker_thread( std::function< void( ) > proc )
    {
            std::cout << "execute in worker thread\n";
            proc();
    }

    template < class... TArgs >
    std::function< void( TArgs... ) >
    schedule( std::function< void( TArgs... ) > proc )
    {
        std::function< void( TArgs... ) > f
                = [this, proc]( TArgs... args ) { run_in_worker_thread( [=]( ) { proc( args... ); } ); };
        return f;
    }  
};

int main()
{
    Test test;
    std::function<void(int, int)> my_funciton = 
         [](int a, int b) {std::cout << "got " << a << " and " << b << "\n";};
    auto f2 = test.schedule( my_funciton );
    f2(1, 2);
    return 0;
}

The problem is that my schedule() requires std::function as argument. For instance, the following call leads to a compilation error:

    auto my_funciton = [](int a, int b) {std::cout << "got " << a << " and " << b << "\n";};
    auto f2 = test.schedule( my_funciton );

Solution

  • The issue is that a std::function is a polymorphic wrapper around a callable object. Lambdas are not std::functions. Just like string literals are not std::strings. In your first example, you do this:

    std::function<void(int, int)> my_funciton = 
         [](int a, int b) {std::cout << "got " << a << " and " << b << "\n";};
    

    You're constructing a std::function from the lambda. The schedule function is able to deduce the signature of the function without problems.

    In your second example, you do this:

    auto my_funciton = [](int a, int b) {std::cout << "got " << a << " and " << b << "\n";};
    

    Then you get an error because std::function<void (Args...)> can't be matched against the lambda. The solution to this is to allow schedule to accept any callable object, not just std::function.

    template <typename Func>
    auto schedule(Func proc) {
      return [this, proc](auto... args) {
        run_in_worker_thread([=]() {
          proc(args...);
        });
      };
    }