【问题标题】:error in accessing surrounding variable in lambda function在 lambda 函数中访问周围变量时出错
【发布时间】:2020-05-06 01:55:31
【问题描述】:
...
        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&lt;std::__cxx11::string, int&gt;' (aka 'const unordered_map&lt;basic_string&lt;char&gt;, int&gt;')

但如果我不使用 [] 运算符而是使用 .at() 进行访问。代码编译。

我不知道为什么。我检查了 [] 运算符和 .at() :两者都具有相同的方法签名。

【问题讨论】:

  • 进行 4 次查找而不是 2 次查找并不是一个好主意,它在无序地图上非常有效,但仍然如此。您可能希望将这些字符串作为 const 引用传递,而不是在每次比较时复制它们。

标签: c++ c++11 lambda function-call-operator


【解决方案1】:

我检查了 [] 运算符和 .at() :两者具有相同的方法签名。

没有。 std::map::operator[] 不能在 const map 上调用。它可能会修改map(如果指定的键不存在)。 (顺便说一句,std::map::at 不会修改 map,如果指定的密钥不存在,它会抛出 std::out_of_range。)

您可以用mutable 标记lambda;否则 lambda 的 operator() 是 const-qualfied 并且通过副本捕获的对象也是 const,那么你不能在它上面调用 operator[]

可变:允许 body 修改复制捕获的对象,并 调用它们的非常量成员函数

除非在 lambda 表达式中使用了关键字 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】:

    在 lambda 中捕获的变量默认为 const,除非您将 lambda 标记为 mutableunordered_map 没有可以在const unordered_map 对象上调用的operator[],因为如果找不到请求的键,它会插入(即修改)一个新元素。

    另外,您正在捕获map按值,您应该按引用捕获它(除非您期望cmpmap 寿命更长)。

    试试这个:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-06-23
      • 2014-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-02
      • 1970-01-01
      相关资源
      最近更新 更多