将 lambda 作为参数传递给带有任意数量参数的 std::function 参数的函数

Eug*_*yev 16 c++ lambda templates metaprogramming function

考虑下一个代码示例:

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

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

为什么我可以这样做:

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

但这样做时出现编译错误:

int main() {
// Function call
    foo<int, int>(
        [](int a, int b) {}
    );
}
Run Code Online (Sandbox Code Playgroud)
<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) {
     ^
Run Code Online (Sandbox Code Playgroud)

我只是想有一种方便的方式来使用诸如foo.

我试过这个:


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

    foo<int, int>(f); // ok
Run Code Online (Sandbox Code Playgroud)

它奏效了。这没关系。但我想知道是否有任何方法可以在函数调用中使用 lambda,而不创建本地函数对象。

Art*_*yer 17

因此:为什么在函数参数类型中使用模板参数包,因为它的模板参数列表无法显式指定

当您调用 时foo<int, int>([](int a, int b) {});,仍会扣除该包TArgs,以防需要扩展。无法使用 lambda 参数std::function<void(TArgs...)>推导出任何内容,因此它被推导为空包,这与给定的.TArgs...int, int

对于Class<int, int>::foo,没有模板参数推导,因为模板参数已经给出。

解决这个问题的方法是将其放在非推导的上下文中:

template <typename... TArgs>
void foo(std::type_identity_t<std::function<void(TArgs...)>> f) {
}
Run Code Online (Sandbox Code Playgroud)

std::function或者根本不采取:

template <typename F>
void foo(F&& f) {
}
Run Code Online (Sandbox Code Playgroud)