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

pass lambda to function that accepts function with templated types

本文关键字:函数 类型 lambda      更新时间:2023-10-16

我正在尝试创建一个模板函数,它将一个函数作为形参,并且形参函数具有供模板推断的参数。

的例子:

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

void func_a(void(*func)(int)) {
    func(1);
}
int main() {
    auto f = [](int x) -> void { printf("%in", 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("%in", x); };
    func_b(f);       // neither of
    func_b<int>(f); // these work
    return 0;
}

理想情况下,我希望func_b接受常规函数和lambda函数,如func_a所做的,但与模板魔术。

不幸的是,模板演绎不能很好地处理隐式转换。但是,可以显式地将lambda转换为函数指针类型。最短但有些令人困惑的方法是应用一元+操作符:

func_b(+f);

或者您可以使用更直观的,但也冗长且违反dry的强制转换操作:

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

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

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

这在lambdas中工作得很好。不涉及转换

func_c(f);

并且它也适用于捕获lambda(不能转换为函数指针),std::function和函数对象,例如在<functional>中定义的那些。

这里有一些可用的选项:

#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("%in", 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对象。

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

func_d(和func_d1)结合了其他方面。它转发lambda并显式地从中生成std::function -object,尽管它需要一个额外的模板参数。