在 lambda 函数中访问周围变量时出错
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];
};
...
这个给我no viable overloaded operator[] for type 'const unordered_map<std::__cxx11::string, int>' (aka 'const unordered_map<basic_string<char>, int>')
但是如果我不使用 [] 运算符而是使用 .at() 进行访问。代码编译。
我不知道为什么。我检查了 [] 运算符和 .at() :两者都具有相同的方法签名。
I check out [] operator and .at() : both have the same method signature.
没有。 std::map::operator[]
can't be called on const
map
. It might modify the map
(if specified key doesn't exist). (BTW std::map::at
不会修改 map
,如果指定的键不存在,它会抛出 std::out_of_range
。)
你可以用 mutable
标记 lambda;否则 lambda 的 operator()
是 const-qualified 并且通过复制捕获的对象也是 const
,那么你不能在它上面调用 operator[]
。
mutable: allows body to modify the objects captured by copy, and to
call their non-const member functions
Unless the keyword mutable was used in the lambda-expression, the
function-call operator is const-qualified and the objects that were
captured by copy are non-modifiable from inside this operator()
.
例如
auto cmp = [map](string s1, string s2) mutable {
if (map[s1] == map[s2])
return s1 < s2;
return map[s1] > map[s2];
};
PS: 不对变量使用名称 map
是个好主意。
lambda 中捕获的变量默认为 const
,除非您将 lambda 标记为 mutable
。 unordered_map
没有可以在 const unordered_map
对象上调用的 operator[]
,因为如果请求,它会插入(即 修改 )一个新元素找不到密钥。
此外,您正在 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 < ?
};
...
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() :两者都具有相同的方法签名。
I check out [] operator and .at() : both have the same method signature.
没有。 std::map::operator[]
can't be called on const
map
. It might modify the map
(if specified key doesn't exist). (BTW std::map::at
不会修改 map
,如果指定的键不存在,它会抛出 std::out_of_range
。)
你可以用 mutable
标记 lambda;否则 lambda 的 operator()
是 const-qualified 并且通过复制捕获的对象也是 const
,那么你不能在它上面调用 operator[]
。
mutable: allows body to modify the objects captured by copy, and to call their non-const member functions
Unless the keyword mutable was used in the lambda-expression, the function-call operator is const-qualified and the objects that were captured by copy are non-modifiable from inside this
operator()
.
例如
auto cmp = [map](string s1, string s2) mutable {
if (map[s1] == map[s2])
return s1 < s2;
return map[s1] > map[s2];
};
PS: 不对变量使用名称 map
是个好主意。
lambda 中捕获的变量默认为 const
,除非您将 lambda 标记为 mutable
。 unordered_map
没有可以在 const unordered_map
对象上调用的 operator[]
,因为如果请求,它会插入(即 修改 )一个新元素找不到密钥。
此外,您正在 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 < ?
};