When we are defining a lambda, we have the possibility to capture variables of the enclosing scope such that they become available in the body of the lambda [2.1.7.0]. In practice, such variables are either copied (like var1 below, due to the = syntax), or referenced (like var2 below, with the & syntax).
const auto foo = [=var1, &var2]() -> void {};
Unfortunately there is no other variant of the capture, which leads to situations like this:
void wait_for_new_players(const std::string& group) { std::string display_label = group + ": "; // Copies are striking again. Here display_label is copied into a // field of the function object associated with this lambda; not // moved nor initialized on construction. auto add_player_to_list = [display_label](player_id id, const std::string& player alias) { m_player_list->add(id, display_label + alias); }; m_team_service.wait_for_players(group, add_player_to_list); }
In the above example, we would want to avoid the copy of the display label into the equivalent member variable of the lambda. In C++11 there is only two ways to achieve that: either by creating the display label in the callback’s body, thus creating a new string on each call2, or by using a custom function object, C++98-style.
Additionally, we can note that this behavior prevent any use of a move-only type for a captured variable, such as std::unique_ptr. Indeed, there is no way to move the variable from the outer scope into the lambda.
In C++14, capture lists have been extended to allow the initialization of a variable by an expression. We can use that to initialize the display label with the final string directly:
void wait_for_new_players(std::string group) { // display_label is initialized directly in the construction of the // lambda, thus saving a copy. auto add_player_to_list = [display_label =group+":"] (player_id id, const std::string& alias) { m_player_list.add(id, display_label + alias); }; m_team_service.wait_for_players(group, add_player_to_list); }
This also solves the move-only type situation since we can now move the variable:
void apply_filter(std::vector<int>& values, std::unique_ptr<filter> filter)
{
std::for_each
(values.begin(), values.end(),
[f
=std::move(filter)](int& v) -> void
{
v = f->transform(v);
});
}
2We would also have a copy of the captured group variable anyway.