Abhishek Bansal
Abhishek Bansal

Reputation: 5335

How to capture function arguments and store function pointer for later execution in C++11?

My requirement is to store some functions for later execution with pre-defined arguments. Here is what I have tried

void doSomething(int i, int j) {
    std::cout << "Sum " <<  i + j << std::endl;
}

int main(int argc, char *argv[]) {
    std::vector<std::function<void(int, int)>> functionVector;

    functionVector.push_back(std::bind(doSomething, 1, 2));
    functionVector.push_back(std::bind(doSomething, 4, 2));

    functionVector[0]();
    functionVector[1]();
}

However this does not compile and gives following error

error: no matching function for call to object of type 'std::__1::__vector_base<std::__1::function<void (int, int)>,
      std::__1::allocator<std::__1::function<void (int, int)> > >::value_type' (aka 'std::__1::function<void (int, int)>')
    functionVector[0]();
    ^~~~~~~~~~~~~~~~~

How can I achieve this in C++11/14?

Upvotes: 2

Views: 267

Answers (1)

walnut
walnut

Reputation: 22152

After binding the arguments to the function, the call doesn't take any further arguments anymore. Therefore the function type should be void():

std::vector<std::function<void()>> functionVector;

Also note that you can use lambdas in C++11 and later, which are more flexible than std::bind:

functionVector.push_back([](){ doSomething(1, 2); });
functionVector.push_back([](){ doSomething(4, 2); });

or slightly simplified, empty parameter lists can be omitted:

functionVector.push_back([]{ doSomething(1, 2); });
functionVector.push_back([]{ doSomething(4, 2); });

As you can see the lambdas don't have any parameters here and so the type of their call operators is void().


Although it won't make any real difference, I would also suggest you to use emplace_back (since C++11) instead of push_back.

push_back expects a reference to the element type (here std::function<void()>), but since you are passing it something else, the std::function<void()> will first be constructed as a temporary for the push_back parameter and then the vector element with be move-constructed from it.

emplace_back on the other hand expects the constructor arguments for the vector element and will construct the std::function<void()> object directly in-place without intermediate temporary.


In this specific instance std::function is also unnecessary when using lambdas, since lambdas without capture decay to function pointers, which you can store as a lightweight alternative to std::function:

std::vector<void(*)()> functionVector;

If you intend to store lambdas with capture, then the std::function approach is required.

Upvotes: 6

Related Questions