是否可以将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&&'
这是一个要消化的错误消息,但我认为我从中得到的是不能作为constexpr处理,因此我不能将它作为函数指针传递?我也试着让x成为constexpr,但这似乎没有帮助。
虽然模板方法出于各种原因很聪明,但重要的是要记住lambda和捕获的变量的生命周期。如果要使用任何形式的lambda指针is,并且lambda不是向下延续,那么只应该使用复制[=]lambda。也就是说,即使这样,如果捕获的指针的生命周期(堆栈unwind)比lambda的生命周期短,那么在堆栈上捕获一个指向变量的指针也是不安全的。
捕获lambda作为指针的一个更简单的解决方案是:
auto pLamdba = new std::function<...fn-sig...>([=](...fn-sig...){...});
例如,新std::函数<空白 ()>([=]() -> 空白{…}
只需要记住稍后删除pLamdba,以确保不会泄漏lambda内存。
这里要意识到的秘密是lambdas可以捕获lambdas(问问自己这是如何工作的),而且为了让std::function正常工作,lambda实现需要包含足够的内部信息来提供对lambda(和捕获的)数据大小的访问(这就是为什么delete应该工作[运行捕获类型的析构函数])。
正如其他人提到的,你可以用Lambda函数代替函数指针。我使用这个方法在我的c++接口到F77 ODE求解器RKSUITE。
//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);
如果lambda没有捕获,则只能将其转换为函数指针,摘自c++ 11标准草案5.1.2节[expr.prim. xml]。Lambda]表示(强调我的):
没有lambda捕获的lambda表达式的闭包类型具有
到指针的公共非虚拟非显式const转换函数
函数具有与闭包相同的参数和返回类型
类型的函数调用操作符。此转换返回的值
Function应是函数的地址,该函数在调用时具有
与调用闭包类型的函数调用操作符的效果相同。
注意,cppreference在Lambda函数一节中也介绍了这一点。
因此,以下选择是可行的:
typedef bool(*DecisionFn)(int);
Decide greaterThanThree{ []( int x ){ return x > 3; } };
这个也一样:
typedef bool(*DecisionFn)();
Decide greaterThanThree{ [](){ return true ; } };
正如5gon12eder所指出的,您也可以使用std::function,但请注意std::function是很重要的,所以它不是一个无成本的权衡。
这不是一个直接的答案,而是使用“functor”模板模式来隐藏lambda类型的细节,并保持代码的美观和简单。
我不确定你想如何使用决定类,所以我必须用一个使用它的函数扩展类。完整示例请参见:https://godbolt.org/z/jtByqE
类的基本形式可能是这样的:
template <typename Functor>
class Decide
{
public:
Decide(Functor dec) : _dec{dec} {}
private:
Functor _dec;
};
将函数类型作为类类型的一部分传入,如下所示:
auto decide_fc = [](int x){ return x > 3; };
Decide<decltype(decide_fc)> greaterThanThree{decide_fc};
再一次,我不确定为什么你要捕捉x它更有意义(对我来说)有一个参数,你传递给lambda),所以你可以像这样使用:
int result = _dec(5); // or whatever value
有关完整示例,请参见链接
使用lambda with作为C函数指针的快捷方式是:
"auto fun = +[](){}"
以Curl为例(Curl调试信息)
auto callback = +[](CURL* handle, curl_infotype type, char* data, size_t size, void*){ //add code here :-) };
curl_easy_setopt(curlHande, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curlHande,CURLOPT_DEBUGFUNCTION,callback);