c++c++11lambdafunction-call-operator

error in accessing surrounding variable in lambda function


...
        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];
        };
...

This give me no viable overloaded operator[] for type 'const unordered_map<std::__cxx11::string, int>' (aka 'const unordered_map<basic_string<char>, int>')

But if I don't use [] operator but rather use .at() for access. The code compiles.

I don't know why. I check out [] operator and .at() : both have the same method signature.


Solution

  • Variables captured in a lambda are const by default, unless you mark the lambda as mutable. unordered_map does not have an operator[] that can be called on a const unordered_map object, since it inserts (ie modifies) a new element if the requested key is not found.

    Also, you are capturing map by value, you should capture it by reference instead (unless you are expecting cmp to outlive map).

    Try this:

    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 < ?
    };