为什么在这种情况下 lambda 没有转换为函数?

Why is lambda not converted to function in this case?

我正在使用参数包和 std::function 编写代码。目标是能够将一个函数和一组参数传递给一个函数,并能够调用该参数包的函数(并做一些其他工作)。这是我想要的精简示例:

#include <functional>
#include <iostream>

template<typename... Args>
using MyFunc = std::function< void(Args...) >;

template<typename... Args>
void call(MyFunc<Args...> f, Args... args) {
    f(args...);
}

int main() {
    auto lambda = [](int a, double b) {std::cout << a << b << std::endl;};
    call<int, double>(lambda, 1, 2.0);
    // but this works?
    //call(MyFunc<int, double>(lambda), 1, 2.0);

    return 0;
}

当我用 clang 13.0 编译它时,我得到:could not match 'function<void (int, double, type-parameter-0-0...)>' against '(lambda at pack.cpp:13:19)'。 对于 g++ 7.5,我得到类似的:‘main()::<lambda(int, double)>’ is not derived from ‘std::function<void(Args ...)>’.

如您所见,我评论了一个有效的示例:将参数显式转换为 std::function。但为什么它不能隐含地做到这一点?

P.S。我不能使用模板 F 而不是 std::function ,原因超出了这个简单示例的范围。

问题是第一个函数参数 fArgs 的模板参数推导失败,因为推导中不会考虑隐式转换(从 lambda 到 std::function)。

您可以使用 std::type_identity(C++20 起;为 C++20 之前的版本编写一个非常容易)从推导中排除 f。例如

template<typename... Args>
void call(std::type_identity_t<MyFunc<Args...>> f, Args... args) {
    f(args...);
}

顺便说一句,即使指定了模板参数,仍会执行模板参数推导以确定参数包的结尾。在这种情况下,您不需要指定它们,您可以将其称为 call(lambda, 1, 2.0);.