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

16

考虑下面的代码示例:

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

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

为什么我可以做这个:
int main() {
// Helper class call
    Class<int, int>::foo(
        [](int a, int b) {}
    );
}

但是我这样做会得到一个编译错误:

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) {
     ^

我只想要一个方便的方法来使用像 foo 这样的函数。
我已经尝试过这个:

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

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

它有效了。这没问题。但我想知道是否有一种方式可以在函数调用中直接使用lambda,而无需创建本地函数对象。

1个回答

17

由于这个原因:为什么在函数参数类型中使用模板参数包作为其模板参数列表时无法显式指定?

当你调用foo<int, int>([](int a, int b) {});时,模板参数包TArgs仍然会被推导,以防需要扩展它。 std::function<void(TArgs...)>不能针对带有 lambda 参数的TArgs...进行任何推导,因此它将被推导为空的包,与给定的int,int相冲突。

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

解决方法是将其放在非推导上下文中:

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

或者干脆不使用std::function

template <typename F>
void foo(F&& f) {
}

1
或者将其包装在一个类中以防止像 OP 一样进行推断 ;) - 463035818_is_not_a_number
1
或者 static_cast<void(*)(std::function<void(int, int)>)>(&foo)([](int, int){}); - Jarod42

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接