As usual, Scott Meyers offers a great explanation of what they are, why you would want to use them, and roughly what rules they follow, in Effective Modern C++ Item 32: Use init capture to move objects into closures. Here is a short summary:
Since C++11 only has by-value and by-reference capture, by-move capture was missing. Instead of adding it, C++14 introduced the generalized lambda capture, also known as init capture. It allows you to specify
- the name of a data member in the closure class generated from the lambda, and
- an expression initializing that data member.
With this, an init capture is a new and more general capture mechanism, which covers the three above by-* captures and more (but no default capture mode).
Coming back to the main motivation of by-move capture, it can be implemented by an init capture as follows:
auto pw = std::make_unique<Widget>();
// configure *pw
auto func = [pWidget = std::move(pw)] {
return pWidget->isValidated() && pWidget->isArchived();
};
You can simulate an init capture in C++11 with
a hand-written class:
class IsValAndArch {
public:
using DataType = std::unique_ptr<Widget>;
explicit IsValAndArch(DataType&& ptr) : pw(std::move(ptr)) {}
bool operator()() const { return pw->isValid() && pw->isArchived(); }
private:
DataType pw;
};
auto pw = std::make_unique<Widget>();
// configure *pw;
auto func = IsValAndArch(pw);
or with std::bind
:
auto pw = std::make_unique<Widget>();
// configure *pw;
auto func = std::bind( [](const std::unique_ptr<Widget>& pWidget)
{ return pWidget->isValidated() && pWidget->isArchived(); },
std::move(pw) );
Note that the parameter for the lambda is an lvalue reference (because the moved pw
within the bind object is an lvalue) and has a const qualifier (to simulate the lambda's constness; so if the original lambda were declared mutable, the const qualifier would not be used).
Some details about init captures is also given in Anthony Calandra's cheatsheet of modern C++ language and library features, for instance that the initializing expression is evaluated when the lambda is created (not when it is invoked).