#c #c 11 #lambda
#c #c 11 #лямбда
Вопрос:
Я пробовал что-то подобное, чтобы предварительно заполнить карту, используя векторный список строк. Код не требует пояснений:
Constructor(const vector<string>amp; names) {
for_each(names.begin(), names.end(),
[this, counter = 1](const Stringamp; choice) mutable {
nameMapping.emplace(choice, counter );
}
);
}
Что-то, что я действительно не понял, так это то, как это counter
работает?
К вашему сведению: counter
нигде не объявлено вне лямбда-функции.
Но все же я могу создать локальную переменную в области видимости класса и изменить ее в изменяемом лямбда-fn?
Может кто-нибудь, пожалуйста, помочь мне понять, что происходит.
Комментарии:
1. В основном, происходит то, как работают лямбда-захваты. Тип захваченных переменных выводится из типа выражения, которое его инициализирует. Здесь действительно больше нечего сказать, кроме того, как работают лямбды C .
2. Это как если бы вы могли писать
auto counter = 1
.
Ответ №1:
Когда вы устанавливаете counter = 1
, вы объявляете новое временное counter
значение, равное 1. Компилятор выполняет работу по определению типа. Этот временный объект int
по умолчанию выводится в type и существует, пока лямбда активен.
Установив mutable
, вы можете как изменять counter
, так и this
Кроме того: поскольку кажется, что вы вставляете в карту / неупорядоченную карту, вам, вероятно, лучше использовать следующее:
#include <algorithm> // For transform
#include <iterator> // For inserter
Constructor(const vector<string>amp; names) {
auto const example = [counter = 1](const stringamp; item) mutable {
return {item, counter };
};
std::transform(names.begin(), names.end(),
std::inserter(nameMapping, nameMapping.end()), example);
}
Перемещая вызов сопоставления имен за пределы лямбда-выражения, вам не нужно путать себя с тем, что находится в области видимости, а что нет.
Кроме того, вы можете избежать ненужных захватов и всего остального, что может сбить с толку вас или других читателей в будущем.
Комментарии:
1. «Этот временный объект выводится с типом int по умолчанию» Потенциально запутанное использование термина «по умолчанию» здесь; это только
int
потому, что литерал1
является anint
.2. В любом случае вам не нужно никаких сложностей. Лямбда, захват,
mutable
,std::transform
,std::inserter
, два заголовка… почему ?! Все, что вам нужно, это объявить, аint
затем написать двухстрочныйfor
цикл. Это действительно очень просто.
Ответ №2:
Но все же я могу создать локальную переменную в области видимости класса и изменить ее в изменяемом лямбда-fn?
Может кто-нибудь, пожалуйста, помочь мне понять, что происходит.
Все именно так, как вы сказали.
Возможно, это сбивает с толку, потому что в этом конкретном объявлении не указан тип. Лично я думаю, что это было ужасное дизайнерское решение, но мы идем.
Представьте auto counter = 1
, что вместо этого говорится; auto
это сделано для вас. Затем переменная становится «членом» лямбда-объекта, присваивая ему состояние.
Код не очень хорош, потому что не гарантируется, что лямбда-выражение будет применено к элементам контейнера по порядку. Простой for
цикл, возможно, был бы намного проще, понятнее и предсказуем:
Constructor(const vector<string>amp; names)
{
int counter = 1;
for (const stringamp; name : names)
nameMapping.emplace(name, counter );
}
На самом деле нет причин усложнять ситуацию только ради использования «причудливых» стандартных алгоритмов.