hiapay
hiapay

Reputation: 71

C++ Functions with lambdas as arguments

I have an overload function, with the following signatures:

void Foo(const std::function<void(int     )> &func);
void Foo(const std::function<void(int, int)> &func);

And when I want to use Foo() with lambdas, I'll have to do something like this:

Foo((std::function<void(int     )>) [] (int i       ) { /* do something */ });
Foo((std::function<void(int, int)>) [] (int i, int j) { /* do something */ });

Both of which are not so user-friendly. It'd be a lot easier to use the function without having to add the casting "(std::function<...>)" before the lambdas - like this:

    Foo([] (int i       ) { /* do something */ }); // executes the 1st Foo()
    Foo([] (int i, int j) { /* do something */ }); // executes the 2nd Foo()

So, I need another overload, that accept lambda as its argument, and which automatically casts the lambda to one of the above signatures. How can this be done? Or, is it possible in the first place?

template <typename Function> void Foo(Function function) {
    // insert code here: should be something like
    //   - check the signature of the 'function'; and
    //   - call 'Foo()' corresponding to the signature
}

Please help.

PS. I'm using VS2010.

Upvotes: 0

Views: 385

Answers (2)

dascandy
dascandy

Reputation: 7302

Lambda's convert to std::function<> implicitly, there's no explicit conversion needed.

std::function<void(int, int)> func = [](int a, int b){ printf("Hello Lambda world!"); };
func(1, 2);

Ah, you're trying to get a const reference to it. Why though? You should be better off with a right-hand reference (as it's a temporary) or a copy. In both of those cases it should implicitly convert as well...

Upvotes: 1

Jon Purdy
Jon Purdy

Reputation: 55069

If your lambda does not capture any variables—that is, it begins with []—then it is convertible to a function pointer, and you can declare Foo like so:

void Foo(void(*func)(int));
void Foo(void(*func)(int, int));

If you want to keep the std::function versions, you can have these versions forward to that one. If you don’t want to implement them separately, I think a variadic template would do nicely:

template<class... Args>
void Foo(void(*func)(Args...)) {
    return std::function<void(Args...)>(func);
}

If your lambdas capture variables, then they’re not convertible to function pointers, and you’ll need to wrap them in std::function yourself.

Upvotes: 3

Related Questions