Maxian Nicu
Maxian Nicu

Reputation: 2294

C++ universal function caller

I'd want to implement a function caller that works just like the thread constructor. For example

std::thread second (bar,0);

will start a thread which calls bar with the single argument 0. I would like to do the same thing, but I do not know how.

For example, given:

void myFunc(int a){
    cout << a << endl;
}

I would like:

int main() {
    caller(myFunc,12);
}

to call myFunc with the parameter 12.

Upvotes: 10

Views: 2390

Answers (2)

Barry
Barry

Reputation: 303337

If all you want to do is call an arbitrary function with an arbitrary argument, that's just a template on both types:

template <typename Function, typename Arg>
void call_with_one(Function&& f, Arg&& arg) {
    f(std::forward<Arg>(arg));
}

which you can expand to call with any number of args by making it variadic:

template <typename Function, typename... Arg>
void call_with_any(Function f, Arg&&... args) {
    f(std::forward<Arg>(args)...);
}

Or really f should be a forwarding reference as well:

template <typename Function, typename... Arg>
void call_with_any(Function&& f, Arg&&... args) {
    std::forward<Function>(f)(std::forward<Arg>(args)...);
}

Note that this will only work with functions and objects that implement operator(). If f is a pointer-to-member, this will fail - you will have to instead use std::bind as Mike Seymour suggests.

Upvotes: 7

Mike Seymour
Mike Seymour

Reputation: 254621

std::bind will make a callable object from any callable object with an arbitrary set of parameters, just as the thread constructor does. So just wrap that in a function that calls it:

template <typename... Args>
auto caller(Args &&... args) {
    return std::bind(std::forward<Args>(args)...)();
}

Note that the auto return type requires C++14 or later. For C++11, you'll have to either return void, or specify the type:

auto caller(Args &&... args) 
    -> decltype(std::bind(std::forward<Args>(args)...)())

Upvotes: 21

Related Questions