Working with lambdas is great in c++, but sometimes you want to make recursive lambdas, there are a few pitfalls that I've been in. I'm listing them here to pull me (or you!) out in the future :)
Gotcha's
bad_function_call issue
The following code example produces a bad function call due to capturing the lambda by value:
// Declaration
std::function<void(const SBone*, const core::vector3df&, const core::quaternion&)> f_build;
f_build = [f_build](const SBone* bone, const core::vector3df& pos, const core::quaternion& rot)
{
// This will cause a "bad call" due to incomplete capture of f_build
f_build(bone, pos, rot);
};
Corrected Code
The issue is resolved by capturing the lambda by reference:
// Declaration
std::function<void(const SBone*, const core::vector3df&, const core::quaternion&)> f_build;
f_build = [&f_build](const SBone* bone, const core::vector3df& pos, const core::quaternion& rot)
{
// This will correctly call the fully initialized f_build
f_build(bone, pos, rot);
};
Explanation
Here's why capturing by value causes a "bad call":
- Copy of
f_build
: When capturing by value, the lambda captures a copy of thef_build
variable. However, at the point of the lambda's creation,f_build
is not fully initialized. It is still being defined, leading to an incomplete or invalid function. - Uninitialized or Incomplete State: The lambda inside the
f_build
variable refers to an incomplete or invalid function, which results in a "bad call" when the lambda tries to invoke itself. - Reference to
f_build
: Capturingf_build
by reference ([&f_build]
) ensures that the lambda uses the actualf_build
variable, which will eventually hold the fully initialized lambda function. - Correct Recursive Call: By capturing by reference, the recursive call inside the lambda correctly invokes the complete and fully initialized lambda function, allowing recursion to work as intended.