如何使用模板将lambda转换为std :: function

基本上,我想要能够做的就是带任意数量的任何types的参数的lambda,并将其转换为一个std ::函数。 我已经尝试了以下两种方法的工作。

std::function([](){});//Complains that std::function is missing template parameters template <typename T> void foo(function<T> f){} foo([](){});//Complains that it cannot find a matching candidate 

下面的代码可以工作,但是这不是我想要的,因为它需要显式声明不适用于generics代码的模板参数。

 std::function<void()>([](){}); 

我一直在使用函数和模板整夜,我只是无法弄清楚,所以任何帮助将不胜感激。

正如在评论中提到的,我试图做到这一点的原因是因为我试图使用可变参数模板在C ++中实现柯里化。 不幸的是,这在使用lambda时会失败。 例如,我可以使用函数指针传递一个标准函数。

 template <typename R, typename...A> void foo(R (*f)(A...)) {} void bar() {} int main() { foo(bar); } 

但是,我不知道如何将lambda传递给这样一个可变参数的函数。 为什么我有兴趣将genericslambda转换成std :: function是因为我可以做到以下几点,但是最终它要求我明确地将模板参数声明为std :: function,这正是我想要避免的。

 template <typename R, typename...A> void foo(std::function<R(A...)>) {} int main() { foo(std::function<void()>([](){})); } 

您不能将一个lambda函数对象作为std::function<T>types的parameter passing,而不显式指定模板参数T 模板types演绎尝试将您的lambda函数的types与std::function<T>匹配,在这种情况下它不能完成 – 这些types是不一样的。 模板types扣除不考虑types之间的转换。

如果您可以通过其他方式来推断该types,则可能是有可能的。 你可以通过将函数参数包装在一个identitytypes中来做到这一点,以便在试图匹配lambda到std::function (因为依赖types被types演绎忽略)并给出其他参数时不会失败。

 template <typename T> struct identity { typedef T type; }; template <typename... T> void func(typename identity<std::function<void(T...)>>::type f, T... values) { f(values...); } int main() { func([](int x, int y, int z) { std::cout << (x*y*z) << std::endl; }, 3, 6, 8); return 0; } 

这显然不适用于你的情况,因为你不想在后面传递值。

既然你不想指定模板参数,也不想传递可以从中推导出模板参数的其他参数,编译器将不能推导出你的std::function参数的types。

你可以使用专门的/回顾性的演员 。 一旦你有这样的工具

 #include <functional> using namespace std; template<typename T> struct memfun_type { using type = void; }; template<typename Ret, typename Class, typename... Args> struct memfun_type<Ret(Class::*)(Args...) const> { using type = std::function<Ret(Args...)>; }; template<typename F> typename memfun_type<decltype(&F::operator())>::type FFL(F const &func) { // Function from lambda ! return func; } 

你可以对所有的lambdatypes说FFL()把它们转换成std::function的正确版本

 template <typename... Args> void Callback(std::function<void(Args...)> f){ // store f and call later } int main() { Callback(FFL([](int a, float b){ // do something })); return 0; } 

显示

如在推断lambda或“make_function”的任意调用的调用签名中所示,可以从其(单个) operator()推断lambda(或具有单个调用签名的任何其他函子)的调用签名。

 template<typename T> struct remove_class { }; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...)> { using type = R(A...); }; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...) const> { using type = R(A...); }; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...) volatile> { using type = R(A...); }; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...) const volatile> { using type = R(A...); }; template<typename T> struct get_signature_impl { using type = typename remove_class< decltype(&std::remove_reference<T>::type::operator())>::type; }; template<typename R, typename... A> struct get_signature_impl<R(A...)> { using type = R(A...); }; template<typename R, typename... A> struct get_signature_impl<R(&)(A...)> { using type = R(A...); }; template<typename R, typename... A> struct get_signature_impl<R(*)(A...)> { using type = R(A...); }; template<typename T> using get_signature = typename get_signature_impl<T>::type; 

虽然这是一个相当不灵活的方法; 正如R.Martinho Fernandes所说,它不适用于具有多个operator()的函子,也不适用于模板 operator()或函数(C ++ 14)多态lambdaexpression式。 这就是为什么bind推迟其结果types的推理,直到最终的调用尝试。

可以使用派生,decltype,可变参数模板和一些types特征为lambda获取所需的std :: functiontypes:

 namespace ambient { template <typename Function> struct function_traits : public function_traits<decltype(&Function::operator())> {}; template <typename ClassType, typename ReturnType, typename... Args> struct function_traits<ReturnType(ClassType::*)(Args...) const> { typedef ReturnType (*pointer)(Args...); typedef const std::function<ReturnType(Args...)> function; }; template <typename Function> typename function_traits<Function>::function to_function (Function& lambda) { return static_cast<typename function_traits<Function>::function>(lambda); } template <class L> struct overload_lambda : L { overload_lambda(L l) : L(l) {} template <typename... T> void operator()(T&& ... values){ // here you can access the target std::function with to_function(*(L*)this)(std::forward<T>(values)...); } }; template <class L> overload_lambda<L> lambda(L l){ return overload_lambda<L>(l); } } 

我使用它在我的代码是这样的:

ambient::lambda([&](const vector<int>& val){ // some code here // })(a);

PS:在我的真实情况下,我然后将这个std :: function对象及其参数保存在一个通用的内核对象中,以后可以通过虚拟函数按需执行。

不是currying 已经实施了std::bind

 auto sum = [](int a, int b){ return a+b; }; auto inc = std::bind( sum, _1, 1 ); assert( inc(1)==2 ); 

这可能是有趣的: https : //gist.github.com/Manu343726/94769034179e2c846acc

这是我一个月前写的一个实验。 目标是创build一个类仿函数的C ++模板,模仿Haskell的部分调用闭包,即当你用n个参数调用一个带有m参数的函数时,自动创build一个mn argumments的闭包。

这是这个实验可以实现的一个例子:

 int f( int a, int b, int c, int d) { return a+b+c+d; } int main() { auto foo = haskell::make_function( f ); auto a = foo , 1 , 2 , 3; //a is a closure function object with one parameter std::cout << a , 4 << std::endl; //Prints 10 } 

haskell::make_function使用一些types特征来处理不同types的函数实体,包括lambdaexpression式:

 auto f = haskell::make_function( []( int x, int y , int z ){ return x*y*z; } ); auto a = f(1,2); //a is functor with one parameter (Using the alternative C++-like syntax) auto b = a(3); // b is 6 

正如你所看到的,我使用逗号运算符来模仿Haskell语法,但是您可以将其更改为调用操作符来实现您的目标语法。

你完全可以自由地做任何你想要的代码(检查许可证)。