Reputation: 343
I find that if a lambda is a recursive function which is calling itself, then it can't be captured by another lambda as working in a closure in C++.
I have some codes like this:
#include <memory>
#include <functional>
#include <iostream>
class ClassA
{
public:
std::function<void()> FuncA;
void Call()
{
FuncA();
}
};
class ClassB
{
std::unique_ptr<ClassA> pA = std::make_unique<ClassA>();
public:
void Setup()
{
std::function<void(int)> FuncB = [&](int a)
{
std::cout << "a = " << a << std::endl;
if(a > 0)
FuncB(a-1);
};
pA->FuncA = [&]()
{
FuncB(10.0f);
};
}
void Run()
{
Setup();
pA->Call();
}
};
int main() {
ClassB B;
B.Run();
}
a exception will occur when running to calling FuncA, because FuncB in it will be a empty pointer.
My question is why can't I capture a recursive lambda function?
I'm using Visual Studio 2015
EDIT: If capture FuncB by copy in FuncA, then it works if FuncB is not recursive. like this:
class ClassB
{
std::unique_ptr<ClassA> pA = std::make_unique<ClassA>();
public:
void Setup()
{
std::function<void(int)> FuncB = [FuncB](int a)
{
std::cout << "a = " << a << std::endl;
if (a > 0)
FuncB(a - 1);
};
pA->FuncA = [FuncB]()
{
FuncB(10.0f);
};
}
void Run()
{
Setup();
pA->Call();
}
};
Upvotes: 2
Views: 304
Reputation: 7155
Made small modifications to your code, and this works fine:
#include <iostream>
#include <functional>
struct A
{
std::function<void()> fa;
void call() { fa(); }
};
struct B
{
A *pA;
B() {pA=nullptr; }
typedef std::function<void(int)> FB;
FB fb;
void Setup()
{
fb=[&](int i)
{
std::cout << "i = " << i << "\n";
if(i > 0) fb(i-1);
};
if (pA) { pA->fa=[&]() { fb(10.0f); }; }
}
void Run(A*p)
{
pA=p;
Setup();
pA->call();
}
};
int main()
{
A a;
B b;
b.Run(&a);
return 0;
}
Maybe this will help you refine your algorithm.
Upvotes: 1
Reputation: 126418
You're capturing FuncB
by reference, but FuncB
is destroyed when Setup
returns, leaving you with a dangling reference.
If you change FuncB
to be captured by value, then the first lambda captures it before it is initialized, which leads to undefined behavior.
I can't think of any way to get a lambda to capture itself, like you are trying to do.
Upvotes: 3