ошибка доступа к окружающей переменной в лямбда-функции

...
        unordered_map<string ,int> map;
        for (const auto& str : words) {
            map[str]++;
        }
        auto cmp = [map](string s1, string s2){
            if (map[s1] == map[s2])
                return s1 < s2;
            return map[s1] > map[s2];
        };
...

Это дает мне no viable overloaded operator[] for type 'const unordered_map<std::__cxx11::string, int>' (aka 'const unordered_map<basic_string<char>, int>')

Но если я не использую оператор [], а использую.at() для доступа. Код компилируется.

Не знаю почему. Я проверяю оператор [] и.at(): оба имеют одинаковую сигнатуру метода.

2 ответа

Решение

Переменные, захваченные лямбда-выражением: const по умолчанию, если вы не отметите лямбда как mutable. unordered_map не имеет operator[] что можно назвать const unordered_mapобъект, поскольку он вставляет (т.е. изменяет) новый элемент, если запрошенный ключ не найден.

Кроме того, вы снимаете map по значению, вы должны захватить его по ссылке (если вы не ожидаетеcmp пережить map).

Попробуй это:

unordered_map<string, int> word_counts;

for (const auto& str : words) {
    word_counts[str]++;
}

auto cmp = [&word_counts](const string &word1, const string &word2){
    auto iter = word_counts.find(word1);
    int count1 = (iter != word_counts.end()) ? iter->second : 0;
    iter = word_counts.find(word2);
    int count2 = (iter != word_counts.end()) ? iter->second : 0;
    /* or, throw an exception if word1 or word2 are not found...
    int count1 = word_counts.at(word1);
    int count2 = word_counts.at(word2);
    */
    if (count1 == count2)
        return word1 < word2;
    return count1 > count2; // <-- why > and not < ?
};

Я проверяю оператор [] и.at(): оба имеют одинаковую сигнатуру метода.

Нет. std::map::operator[] не может быть вызван const map. Это может изменитьmap(если указанный ключ не существует). (Кстати std::map::at не изменит map, это бросит std::out_of_range если указанный ключ не существует.)

Вы можете отметить лямбду с помощью mutable; в противном случаеoperator() лямбда-выражения определяется константой, а скопированный объект - const тоже тогда ты не можешь позвонить operator[] в теме.

изменяемый: позволяет телу изменять объекты, захваченные копией, и вызывать их неконстантные функции-члены

Если в лямбда-выражении не было использовано ключевое слово mutable, оператор вызова функции квалифицируется как const, а объекты, захваченные копией, не могут быть изменены изнутри этого operator().

например

auto cmp = [map](string s1, string s2) mutable {
    if (map[s1] == map[s2])
        return s1 < s2;
    return map[s1] > map[s2];
};

PS: не использую имя map для переменной было бы неплохо.

Другие вопросы по тегам