====== 2015-03-03 - init via lambda ======
{{ :blog:2015:03:03:lambda_init.png|lambda init}}
today at work i was refactoring simple piece of code -- a c-tor:
struct Sth
{
SomeClass():
name_("sth"),
{
factory_.add("type", builderFunction);
}
std::string name_;
Factory factory_;
};
// ...
Sth sth;
Producer p(sth.name_, sth.factory_);
but due to different separation of concerns, after changes in other locations, i was in a need to put //Producer// into //Sth// as well:
struct Sth
{
SomeClass():
name_("sth"),
producer_(name_, factory_) // Oops - factory_ is not yet initialized!
{
factory_.add("type", builderFunction);
}
std::string name_;
Factory factory_;
Producer producer_;
};
the problem was order -- i needed to initialize //factory_// first (this has been done in a c-tor body so far) and then initialize //producer_//. the obvious solution was to add a helper function, that would return properly-defined factory, and then call it from my c-tor, to initialize class' member:
Factory createFactory()
{
Factory f;
f.add("type", builderFunction);
return f;
}
struct Sth
{
SomeClass():
name_("sth"),
factory_( createFactory() ),
producer_(name_, factory_) // ok - factory_ is now properly initialized
{
}
std::string name_;
Factory factory_;
Producer producer_;
};
this is however a bit non-local. either i had to create function, in a unnamed namespace, inside my implementation, or //detail// namespace if this is all in header,
or create private, static member function to do this work for me.
can this be done better? using [[wp>C++14]] (and [[wp>C++11]], with a bit more code) it can. the idea is to provide a lambda, that would do the initialization and call it in place:
struct Sth
{
SomeClass():
name_("sth"),
factory_( [](){ Factory f; f.add("type", builderFunction); return f; }() ), // note the ending '()'!
producer_(name_, factory_) // ok - factory_ is now properly initialized
{
}
std::string name_;
Factory factory_;
Producer producer_;
};
this way initialization is done in-place, using local code only. more over, there is a good change compiler will catch your drift and simply insert expected code inline, w/o a need to do any function-calling, objects moving, etc...
honestly this pattern is trivial. it is trivial to the point i was surprised i have not used it until now... ;)