我必须在lambda内进行异步调用,并且一旦异步调用终止,我就必须调用lambda本身。
我尝试用代码解释我的问题:
const start = parseInt(request.params.start)
const end = parseInt(request.params.end)
const sql2 =
"SELECT b.gid, b.the_geom, b.cost_s, b.length_m FROM pgr_dijkstra('SELECT gid::bigint as id, source::bigint,"+
"target::bigint, cost_s::double precision as cost," +
"reverse_cost_s::double precision as reverse_cost FROM ways" +
"WHERE the_geom && ST_Expand((SELECT ST_Collect(the_geom)" +
"FROM ways_vertices_pgr WHERE id IN(" + start + "," + end + ")), 0.01)'," +
start + "," + end + ") a LEFT JOIN ways b ON (a.edge = b.gid);"
typedef function<void(int id)> Callback;
AsyncWork1(Callback call, int id, string)
{
//...
call(id);
}
AsyncWork2(Callback call, int id, double, string)
{
//...
call(id);
}
void AsyncWorks(Callback final_callback, int id)
{
Callback lambda = [&lambda, final_callback, id](int next_work) -> void
{
if(next_work == 1)
{
//...
AsyncWork1(lambda, 2, "bla bla");
}
else if(next_work == 2)
{
//...
//the lambda variable no longer exists
AsyncWork2(lambda, 3, 0.0, "bla bla");
}
else if(next_work == 3)
{
//...
final_callback(id);
}
};
lambda(1);
}
问题在于,当代码从“ AsyncWorks(...)”函数退出时,局部变量“ lambda”不再存在。
我已经阅读了几个有关lambda递归的线程,但是我没有找到任何解决方案。
我该如何解决这个问题?
答案 0 :(得分:2)
基本问题是C ++不会将Lambda的this
指针公开给自己。
碰巧的是,在定义某项内容时,有许多语言无法引用其自身。使用称为“ Y Combinator”的技术将其固定在功能语言中。
C ++中的一个简单的y组合器看起来像:
template<class F>
struct y_combinator_t {
F f;
template<class...Args>
auto operator()(Args&&...args)
-> std::result_of_t< F&( y_combinator_t<F>&, Args&&... ) >
{
return f( *this, std::forward<Args>(args)... );
}
};
template<class F>
y_combinator_t<std::decay_t<F>> y_combinate( F&& f ) {
return {std::forward<F>(f)};
}
如果要使用f( *this
或f( f
,我有两种想法,有时我也可以。
使用:
void AsyncWorks(Callback final_callback, int id)
{
Callback lambda = y_combinate(
[final_callback, id]
(auto& self, int next_work)
-> void
{
if(next_work == 1) {
//...
AsyncWork1(self, 2, "bla bla");
} else if(next_work == 2) {
//...
//the lambda variable no longer exists
AsyncWork2(self, 3, 0.0, "bla bla");
} else if(next_work == 3) {
//...
final_callback(id);
}
}
);
lambda(1);
}
基本上,我向lambda函数主体添加了一个隐式self
参数。 operator()
的调用者看不到此参数。
基于this post by myself进行修改的Y组合器。
答案 1 :(得分:0)
Lambda可以隐式捕获自身。演示如何?参见下面的代码,它计算阶乘值。
#include <iostream>
int (* factorial)( const int) = []( const int number)
{
if( number > 1)
{
return number* factorial( number - 1);
}
else
{
return 1;
}
};
int main(int , char *[])
{
int fact = factorial( 7);
std::cout<< "7! = "<< fact<< std::endl;
}
Output 7! = 5040
如果在lambda内部使用了任何变量,则lambda会隐式捕获它,如果未显式捕获它。由于存在内部lambda,因此可以使用引用自己的名称factorial
。
但是,如果使用int (* factorial)( const int) = []( const int number){//implementation };
代替
auto
,则如下,
auto factorial = []( const int number){ //implementation };
然后g ++编译器给出以下错误,
error: use of ‘factorial’ before deduction of ‘auto’
return number* factorial( number - 1);
是因为未推导factorial
的类型,对于相同的控件,auto不会推论块。对于factorial
,名称auto
仅在声明下方可用。
答案 2 :(得分:0)
@Y牛 为了理解您的答案,我不得不花一些时间研究许多c ++功能,值类别,右值,左值,移动构造函数,移动赋值运算符,可变参数模板,具有隐式转换的可变参数模板,result_of_t <>,decay_t <>,forward <>。
但是我还没有东西,为什么在这里加上'&'符号呢?
... std::result_of_t <F&(y_combinator_t<...
我还重写了您的解决方案,以使其针对我的情况更加具体,也使我(以及所有那些使用C ++的初学者)更容易阅读和理解
class y_combinator_t
{
public:
function<void(y_combinator_t*, int, double, string)> callback;
void operator()(int a, double b, string s)
{
this->callback(this, a, b, s);
}
};
y_combinator_t combinator = {
[id_work = 1]
(y_combinator_t* _this, int a, double b, string s) mutable -> void
{
if(id_work == 1)
{
//...
AsyncWork1(*_this, 2, 3.0, "bla bla");
id_work = 2;
}
else if(id_work == 2)
{
//...
AsyncWork2(*_this, 3, 0.0, "bla bla");
id_work = 3;
}
else if(id_work == 3)
{
//...
}
}
};
//Start works
combinator(0, 0, "");