Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing lambda as an argument to a function with std::function parameter with an arbitrary number of parameters

Consider the next sample of the code:

template <typename... TArgs>
void foo(std::function<void(TArgs...)> f) {
}

template <typename... TArgs>
class Class {
public:
    static void foo(std::function<void(TArgs...)> f) {
    }
};

Why can I do this:

int main() {
// Helper class call
    Class<int, int>::foo(
        [](int a, int b) {}
    );
}

But I get a compile error doing this:

int main() {
// Function call
    foo<int, int>(
        [](int a, int b) {}
    );
}
<source>:16:5: error: no matching function for call to 'foo'
    foo<int, int>(
    ^~~~~~~~~~~~~

<source>:4:6: note: candidate template ignored: could not match
    'std::function<void (int, int, TArgs...)>' against 
    '(lambda at <source>:17:9)'

void foo(std::function<void(TArgs...)> f) {
     ^

I just want to have a convenient way to use functions such as foo.

I've tried this:


std::function<void(int, int)> f = [](int a, int b) {
    };

    foo<int, int>(f); // ok

And it worked. And this is ok. But I want to know if there is any way to use lambdas right in the function call, without creating a local function object.

like image 866
Eugene Afanasyev Avatar asked Jan 01 '26 07:01

Eugene Afanasyev


1 Answers

Because of this: Why is template parameter pack used in a function argument type as its template argument list not able to be explicit specified

When you call foo<int, int>([](int a, int b) {});, the pack TArgs is still deduced in case it needs to be extended. std::function<void(TArgs...)> cannot deduce anything for TArgs... with a lambda argument, so it gets deduced as an empty pack, which conflicts with the given int, int.

For Class<int, int>::foo, there is no template argument deduction since the template arguments are already given.

A fix for this is to put it in a non-deduced context:

template <typename... TArgs>
void foo(std::type_identity_t<std::function<void(TArgs...)>> f) {
}

Or don't take a std::function at all:

template <typename F>
void foo(F&& f) {
}
like image 93
Artyer Avatar answered Jan 03 '26 21:01

Artyer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!