ошибка доступа к окружающей переменной в лямбда-функции - PullRequest
0 голосов
/ 06 мая 2020
...
        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 ]

3 голосов
/ 06 мая 2020

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

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

Вы можете пометить лямбду с помощью mutable; в противном случае operator() лямбда квалифицируется как const, а объект, захваченный копией, тоже 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 для переменной не используется было бы неплохо.

2 голосов
/ 06 мая 2020

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

Кроме того, вы захватываете 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 < ?
};
...