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 {};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);
}
Unfortunately there is no other variant of the capture, which leads to situations like this:
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);
}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);
});
}
This also solves the move-only type situation since we can now move the variable:
2We would also have a copy of the captured group variable anyway.