将lambda传递给接受带有模板化类型的函数的函数

时间:2016-09-14 09:26:38

标签: c++ templates c++11 lambda

我正在尝试创建一个模板函数,该函数将函数作为参数,参数函数具有模板推导的参数。

示例时间:

这是一个接受固定函数类型并且可以工作的函数

void func_a(void(*func)(int)) {
    func(1);
}
int main() {
    auto f = [](int x) -> void { printf("%i\n", x); };
    func_a(f);
    return 0;
}

这是我想要做的,扩展第一个例子(这不会编译)

template <typename... T>
void func_b(void(*func)(T...)) {
    func(1);
}
int main() {
    auto f = [](int x) -> void { printf("%i\n", x); };
    func_b(f);       // neither of
    func_b<int>(f); // these work
    return 0;
}

理想情况下,我希望func_b同时接受常规函数和func_a之类的lambda函数,但使用模板魔法。

2 个答案:

答案 0 :(得分:7)

不幸的是,模板推导对隐式转换不起作用。但是,您可以将lambda显式转换为函数指针类型。最简单但有点令人困惑的方法是应用一元+运算符:

func_b(+f);

或者您可以使用更直观,但也更详细和干扰DRY的演员操作:

func_b(static_cast<void(*)(int)>(f));

但也许,您可能只想接受任何可调用类型,而不仅仅是函数指针:

template <class Fun>
void func_c(Fun&& func) {
    func(1);
}

这对lambda很好用。不涉及转换。

func_c(f);

它还可用于捕获lambdas(无法转换为函数指针),std::function和函数对象,例如<functional>中定义的函数对象。

答案 1 :(得分:3)

这里有一些有用的选项:

#include <functional>
template <typename T>
void func_b(T&& func) {
    func(1);
}

template <typename... T>
void func_c(std::function<void(T...)> func) {
    func(1);
}    

template <typename... T>
void func_d1(std::function<void(T...)> func) {
    func(1);
}   

template<typename... Params>
using fun = std::function<void(Params...)>;

template <typename T, typename... P>
void func_d(T& func) {
    func_d1(fun<P...>(func));
}

int main() {
    auto f = [](int x) { printf("%i\n", x); };
    func_b(f);
    func_b(std::function<void(int)>(f));

    func_c(std::function<void(int)>(f));

    func_d<decltype(f),int>(f);
    return 0;
}

问题是:lambda 是函数指针或std::function - object。

func_b使用完美转发,因此T将是lambda的类型而不是std::function对象。

func_c。您不应该将lambda转换为c风格的函数指针。 std::function对象能够执行此转换,但只能显式(按设计),因此您需要显式转换它们。

func_d(和func_d1)结合其他方面。虽然它需要一个额外的模板参数,但它会转发lambda并明确地生成一个std::function - 对象。