Reputation: 1669
I was trying out something like this to pre-populate a map using a vector-list of strings. The code is self-explanatory:
Constructor(const vector<string>& names) {
for_each(names.begin(), names.end(),
[this, counter = 1](const String& choice) mutable {
nameMapping.emplace(choice, counter++);
}
);
}
Something I didnt really understand is how does counter
work?
FYI: counter
is no-where declared outside of the lambda function.
But yet, I am able to create a local-variable in class-scope and modify it in a mutable lambda fn?
Can someone please help me understand whats going on.
Upvotes: 4
Views: 1275
Reputation: 17474
But yet, I am able to create a local-variable in class-scope and modify it in a mutable lambda fn?
Can someone please help me understand whats going on.
It's exactly as you said.
Possibly confusing because there's no type given in this particular kind of declaration. Personally I think that was an awful design decision, but there we go.
Imagine it says auto counter = 1
instead; the auto
is done for you. The variable then becomes a "member" of the lambda object, giving it state.
The code's not great, because the lambda isn't guaranteed to be applied to the container elements in order. A simple for
loop would arguably be much simpler, clearer and predictable:
Constructor(const vector<string>& names)
{
int counter = 1;
for (const string& name : names)
nameMapping.emplace(name, counter++);
}
There's really no reason to complicate matters just for the sake of using "fancy" standard algorithms.
Upvotes: 0
Reputation: 425
When you set counter = 1
you're declaring a new temporary counter
equal to 1. The compiler does the work of determining the type. This temporary object is deduced to type int
by default, and lives while the lambda is alive.
By setting mutable
you can both modify counter
and this
Aside: since it appears that you're inserting into a map/unordered map, you're probably better off with the following:
#include <algorithm> // For transform
#include <iterator> // For inserter
Constructor(const vector<string>& names) {
auto const example = [counter = 1](const string& item) mutable {
return {item, counter++};
};
std::transform(names.begin(), names.end(),
std::inserter(nameMapping, nameMapping.end()), example);
}
By moving the nameMapping call outside of the lambda, you don't have to confuse yourself with what is in scope and what is not.
Also, you can avoid unnecessary captures, and anything else that might confuse yourself or other readers in the future.
Upvotes: 5