C++ lambdas and closures
C++ lambdas and closures
I'm replacing...about 6000 lines of deserialization C code with what I hope is about 3000 lines of C++. The basic existing pattern is like so:
ser_ret_t msgpack_unpack_mystruct(msgpack_object *obj, mystruct_t *d, void *unused = NULL)
{
NEXT_WORK_OBJ(array, i, work_obj);
ret |= msgpack_unpack_line(work_obj, &d->line);
NEXT_WORK_OBJ(array, i, work_obj);
ret |= msgpack_unpack_node(work_obj, &d->leftNode);
//etc....
This is repeated once for each variable within a given struct. array, i, and work_obj are all state variables used by msgpack, and d is an arbitrary structure pointer. NEXT_WORK_OBJ is a preprocessor macro that is needed to adjust the state variables. msgpack_unpack_* is a function with arbitrary parameters.
array
i
work_obj
d
NEXT_WORK_OBJ
msgpack_unpack_*
This is not only verbose, but incomplete, as the underlying buffer continues to be processed even in the case of a failure.
My thought is to replace the state variables with a state/helper class, with the one issue being calling an arbitrary function within the class. I'm handling that by not making the call within the class, but via lambda.
class UnpackHelper
public:
void GetNext(std::function<ser_ret_t(msgpack_object*)> callback)
= callback(m_pWork);
;
NextObj() replaces the preprocessor macro, and adjusts the class internal state variables. Now the client code looks like so:
NextObj()
ser_ret_t msgpack_unpack_mystruct(msgpack_object *obj, mystruct_t *d, void *unused = NULL)
{
UnpackHelper up;
up.GetNext([=](auto pWork) return msgpack_unpack_line(pWork, &d->line); );
up.GetNext([=](auto pWork) return msgpack_unpack_node(pWork, &d->leftNode););
My question is specifically about the client code, and the lambdas. My understanding is that a default capture is happening here, and I further understand that those are not recommended. Because the capture is always going to happen on a member of a pointer passed into the function (d), though, I believe this pattern is safe. Is this correct? Given the thousands of lambdas that will exist, I would like to avoid unnecessary verbosity. Second, is it possible to shorten or remove the parameter list in any way? (auto pWork) is fairly minimal, but...
default capture
d
(auto pWork)
My new, third question, based on learning about Looks like this could work, but buys me nothing but code bloat caused by template expansion.std::function..is my callback mechanism even necessary? std::function looks like something I might be able to use to create an arbitrary call directly within the class. I'm currently looking at the accepted answer here: C++: pass function with arbitrary number of parameters as a parameter to see if it can be applied to my code...without using C-style variadic args.
std::function
std::function
&d->line and &d->leftnode in the last codeblock are not captures?– zzxyz
Aug 27 at 18:48
&d->line
&d->leftnode
The code you post fails to compile as you don't capture
d. Can you fix that typo? means cappture nothing. And once you capture something, lambda does not convert to function pointer...– Yakk - Adam Nevraumont
Aug 27 at 18:49
d
This code will not compile. You need
[=] if you want to implicitly capture d. Doing that though will not allow you to use a function pointer and you will have to switch to using a std::function instead.– NathanOliver
Aug 27 at 18:49
[=]
d
std::function
Part of the "So you want to write a custom heap, now what?" series? Not sure if there's something like Flay for C++ but it shakes out a lot of holes in your test coverage pretty fast.
– tadman
Aug 28 at 21:08
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
There seems to be no capture at all here.
– François Andrieux
Aug 27 at 18:47