4
#include <unordered_map>
#include <string>
#include <iostream>
#include <algorithm>
#include <utility>

int main() 
{
  std::unordered_map<string, int> hash {{"a", 1}, {"b", 2}, {"c", 3}};

  // CaseA(NO-ERROR)
  std::for_each(hash.begin(), hash.end(),
    [](const std::pair<string, int>& p) {
      std::cout << p.first << " => " << p.second << endl;
    }
  );

  // CaseB(NO-ERROR)
  std::for_each(hash.begin(), hash.end(),
    [](const std::pair<string, int> p) {
      std::cout << p.first << " => " << p.second << endl;
    }
  );

  // CaseC(NO-ERROR)
  std::for_each(hash.begin(), hash.end(),
    [](std::pair<string, int> p) {
      std::cout << p.first << " => " << p.second << endl;
    }
  );

  // CaseD(ERROR)
  std::for_each(hash.begin(), hash.end(),
    [](std::pair<string, int>& p) {
      std::cout << p.first << " => " << p.second << endl;
    }
  );

}

Q1>为什么 CaseD 是错误的?

Q2> CaseA是推荐的方式吗?

谢谢

4

2 回答 2

14

value_typefor astd::unordered_map<K,V>是(std::pair<const K,V>注意const)。您不能将 type 的引用绑定到 typestd::pair<K,V>的对象std::pair<const K,V>。您应该使用std::unordered_map<K,V>::value_type而不是尝试直接拼写类型的名称,因为这样可以确保您不会弄错。

如果您想知道,案例 C 的工作原理是因为有一个构造函数可以转换类型,因此这p将是std::unordered_map.

不打算修改容器中元素的 lambda的推荐方法是:

[](const std::unordered_map<std::string,int>::value_type& p)

在问题的前 3 种情况下,元素的副本已完成(性能下降)。从调用者的角度来看,案例 B 和 C 是相同的(在一个函数中,顶级限定符被删除),但从 lambda 案例 B 的定义的角度来看,将确保您不会尝试修改参数(它本身是源的副本)

于 2013-06-25T20:22:27.067 回答
5

你的问题是你的容器里装满了std::pair<const string, int>. 对于案例 1 到 3,std::pair<const string, int>容器中的 可以std::pair<string, int>隐式转换为 a,然后将该临时传递给您的 lambda。

在 C++11 中为容器的每个元素做一些非变异的推荐方法是:

for( auto const& p: hash ) {
  std::cout << p.first << " => " << p.second << endl;
}

这不那么冗长,并且不违反 DRY。在有意义的情况下,更喜欢基于容器的迭代而不是基于迭代器的迭代。

在基于容器的std::算法和auto类型化 lambda 之间,使用这些std::算法将在一两个版本的 C++ 中再次变得更加诱人。即使那样,除非您对使用 lambda 的算法类型进行抽象,否则for_each现在还是很值得怀疑的,因为我们有一个一流的语言功能可以做什么for_each

于 2013-06-25T21:37:16.943 回答