# 传递lambda作为函数指针

``using DecisionFn = bool(*)(); class Decide { public: Decide(DecisionFn dec) : _dec{dec} {} private: DecisionFn _dec; }; int main() { int x = 5; Decide greaterThanThree{ [x](){ return x > 3; } }; return 0; }` `

` `In function 'int main()': 17:31: error: the value of 'x' is not usable in a constant expression 16:9: note: 'int x' is not const 17:53: error: no matching function for call to 'Decide::Decide(<brace-enclosed initializer list>)' 17:53: note: candidates are: 9:5: note: Decide::Decide(DecisionFn) 9:5: note: no known conversion for argument 1 from 'main()::<lambda()>' to 'DecisionFn {aka bool (*)()}' 6:7: note: constexpr Decide::Decide(const Decide&) 6:7: note: no known conversion for argument 1 from 'main()::<lambda()>' to 'const Decide&' 6:7: note: constexpr Decide::Decide(Decide&&) 6:7: note: no known conversion for argument 1 from 'main()::<lambda()>' to 'Decide&&'` `

` `typedef bool(*DecisionFn)(int); Decide greaterThanThree{ []( int x ){ return x > 3; } };` `

` `typedef bool(*DecisionFn)(); Decide greaterThanThree{ [](){ return true ; } };` `

Shafik Yaghmour的答案正确地解释了为什么lambda不能作为函数指针传递。 我想为这个问题展示两个简单的修复。

1. 使用`std::function`而不是原始函数指针。

这是一个非常干净的解决方案。 但是请注意，它包含了类型擦除的一些额外开销（可能是一个虚函数调用）。

` `#include <functional> #include <utility> struct Decide { using DecisionFn = std::function<bool()>; Decide(DecisionFn dec) : dec_ {std::move(dec)} {} DecisionFn dec_; }; int main() { int x = 5; Decide greaterThanThree { [x](){ return x > 3; } }; }` `
2. 使用不捕获任何东西的lambda表达式。

由于你的谓词实际上只是一个布尔常量，所以下面的问题可以很快解决当前的问题。 看到这个答案是一个很好的解释为什么以及如何工作。

` `// Your 'Decide' class as in your post. int main() { int x = 5; Decide greaterThanThree { (x > 3) ? [](){ return true; } : [](){ return false; } }; }` `

Lambda表达式（甚至是捕获的）可以作为一个函数指针来处理！

` `int first = 5; auto lambda = [=](int x, int z) { return x + z + first; }; int(decltype(lambda)::*ptr)(int, int)const = &decltype(lambda)::operator(); std::cout << "test = " << (lambda.*ptr)(2, 3) << std::endl;` `

` `// OT => Object Type // RT => Return Type // A ... => Arguments template<typename OT, typename RT, typename ... A> struct lambda_expression { OT _object; RT(OT::*_function)(A...)const; lambda_expression(const OT & object) : _object(object), _function(&decltype(_object)::operator()) {} RT operator() (A ... args) const { return (_object.*_function)(args...); } };` `

` `auto capture_lambda() { int first = 5; auto lambda = [=](int x, int z) { return x + z + first; }; return lambda_expression<decltype(lambda), int, int, int>(lambda); } auto noncapture_lambda() { auto lambda = [](int x, int z) { return x + z; }; return lambda_expression<decltype(lambda), int, int, int>(lambda); } void refcapture_lambda() { int test; auto lambda = [&](int x, int z) { test = x + z; }; lambda_expression<decltype(lambda), void, int, int>f(lambda); f(2, 3); std::cout << "test value = " << test << std::endl; } int main(int argc, char **argv) { auto f_capture = capture_lambda(); auto f_noncapture = noncapture_lambda(); std::cout << "main test = " << f_capture(2, 3) << std::endl; std::cout << "main test = " << f_noncapture(2, 3) << std::endl; refcapture_lambda(); system("PAUSE"); return 0; }` `

` `template <typename CT, typename ... A> struct function : public function<decltype(&CT::operator())(A...)> {}; template <typename C> struct function<C> { private: C mObject; public: function(const C & obj) : mObject(obj) {} template<typename... Args> typename std::result_of<C(Args...)>::type operator()(Args... a) { return this->mObject.operator()(a...); } template<typename... Args> typename std::result_of<const C(Args...)>::type operator()(Args... a) const { return this->mObject.operator()(a...); } }; namespace make { template<typename C> auto function(const C & obj) { return ::function<C>(obj); } } int main(int argc, char ** argv) { auto func = make::function([](int y, int x) { return x*y; }); std::cout << func(2, 4) << std::endl; system("PAUSE"); return 0; }` `

` `//C interface to Fortran subroutine UT extern "C" void UT(void(*)(double*,double*,double*),double*,double*,double*, double*,double*,double*,int*); // C++ wrapper which calls extern "C" void UT routine static void rk_ut(void(*)(double*,double*,double*),double*,double*,double*, double*,double*,double*,int*); // Call of rk_ut with lambda passed instead of function pointer to derivative // routine mathlib::RungeKuttaSolver::rk_ut([](double* T,double* Y,double* YP)->void{YP[0]=Y[1]; YP[1]= -Y[0];}, TWANT,T,Y,YP,YMAX,WORK,UFLAG);` `

` `static Callable callable; static bool wrapper() { return callable(); }` `

` `#include<type_traits> #include<utility> template<typename Callable> union storage { storage() {} std::decay_t<Callable> callable; }; template<int, typename Callable, typename Ret, typename... Args> auto fnptr_(Callable&& c, Ret (*)(Args...)) { static bool used = false; static storage<Callable> s; using type = decltype(s.callable); if(used) s.callable.~type(); new (&s.callable) type(std::forward<Callable>(c)); used = true; return [](Args... args) -> Ret { return Ret(s.callable(args...)); }; } template<typename Fn, int N = 0, typename Callable> Fn* fnptr(Callable&& c) { return fnptr_<N>(std::forward<Callable>(c), (Fn*)nullptr); }` `

` `void foo(void (*fn)()) { fn(); } int main() { int i = 42; auto fn = fnptr<void()>([i]{std::cout << i;}); foo(fn); // compiles! }` `

` `std::function<void()> func1, func2; auto fn1 = fnptr<void(), 1>(func1); auto fn2 = fnptr<void(), 2>(func2); // different function` `