lambda签名for_each + unordered_map

时间:2022-02-24 18:51:37
#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> Why CaseD is wrong?

Q1>为什么CaseD错了?

Q2> Is it true that CaseA is the recommended way?

Q2> CaseA是推荐的方式吗?

Thank you

2 个解决方案

#1


13  

The value_type for a std::unordered_map<K,V> is std::pair<const K,V> (note the const). You cannot bind a reference of type std::pair<K,V> to an object of type std::pair<const K,V>. You should use std::unordered_map<K,V>::value_type instead of trying to spell the name of the type directly, as that will make sure that you don't get it wrong.

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

In case you wonder, case C works as there is a constructor that enables the conversion of the types, so that p will be a copy of the value in the std::unordered_map.

如果您想知道,案例C可以工作,因为有一个构造函数可以转换类型,因此p将是std :: unordered_map中值的副本。

The recommended way for a lambda that is not meant to modify the elements in the container would be:

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

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

In the first 3 cases in the question a copy of the element is done (performance hit). From the point of view of the caller, cases B and C are the same (in a function, the top level qualifier is dropped), but from the point of view of the definition of the lambda case B will ensure that you don't attempt to modify the argument (which is itself a copy of the source)

在问题的前3个案例中,完成了元素的副本(性能命中)。从调用者的角度来看,案例B和C是相同的(在一个函数中,*限定符被删除),但从lambda案例B的定义的角度来看,将确保你没有尝试修改参数(它本身就是源的副本)

#2


5  

Your problem is that your container is full of std::pair<const string, int>. For case 1 through 3, the std::pair<const string, int> in the container can be converted to a std::pair<string, int> implicitly, and then that temporary passed to your lambda.

您的问题是您的容器充满了std :: pair 。对于情况1到3,容器中的std :: pair 可以隐式转换为std :: pair ,然后临时传递给lambda。 ,int>

The recommended way in C++11 to do something non-mutating for each element of a container is:

C ++ 11中为容器的每个元素执行非变异操作的推荐方法是:

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

which is less verbose, and doesn't violate DRY. Prefer container-based iteration instead of iterator-based iteration when it makes sense.

这不是冗长的,也不会违反DRY。当有意义时,首选基于容器的迭代而不是基于迭代器的迭代。

Between container-based std:: algorithms and auto typed lambdas, using the std:: algorithms is going to become more tempting again in a version or two of C++. Even then, unless you are abstracting over the kind of algorithm you are using your lambda on, for_each is now quite questionable, because we have a first-class language feature that does what for_each does.

在基于容器的std :: algorithms和自动类型的lambda之间,使用std :: algorithms会在一两个C ++版本中再次变得更具诱惑力。即便如此,除非你在使用lambda的算法上进行抽象,否则for_each现在非常值得怀疑,因为我们有一流的语言功能可以完成for_each的功能。

#1


13  

The value_type for a std::unordered_map<K,V> is std::pair<const K,V> (note the const). You cannot bind a reference of type std::pair<K,V> to an object of type std::pair<const K,V>. You should use std::unordered_map<K,V>::value_type instead of trying to spell the name of the type directly, as that will make sure that you don't get it wrong.

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

In case you wonder, case C works as there is a constructor that enables the conversion of the types, so that p will be a copy of the value in the std::unordered_map.

如果您想知道,案例C可以工作,因为有一个构造函数可以转换类型,因此p将是std :: unordered_map中值的副本。

The recommended way for a lambda that is not meant to modify the elements in the container would be:

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

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

In the first 3 cases in the question a copy of the element is done (performance hit). From the point of view of the caller, cases B and C are the same (in a function, the top level qualifier is dropped), but from the point of view of the definition of the lambda case B will ensure that you don't attempt to modify the argument (which is itself a copy of the source)

在问题的前3个案例中,完成了元素的副本(性能命中)。从调用者的角度来看,案例B和C是相同的(在一个函数中,*限定符被删除),但从lambda案例B的定义的角度来看,将确保你没有尝试修改参数(它本身就是源的副本)

#2


5  

Your problem is that your container is full of std::pair<const string, int>. For case 1 through 3, the std::pair<const string, int> in the container can be converted to a std::pair<string, int> implicitly, and then that temporary passed to your lambda.

您的问题是您的容器充满了std :: pair 。对于情况1到3,容器中的std :: pair 可以隐式转换为std :: pair ,然后临时传递给lambda。 ,int>

The recommended way in C++11 to do something non-mutating for each element of a container is:

C ++ 11中为容器的每个元素执行非变异操作的推荐方法是:

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

which is less verbose, and doesn't violate DRY. Prefer container-based iteration instead of iterator-based iteration when it makes sense.

这不是冗长的,也不会违反DRY。当有意义时,首选基于容器的迭代而不是基于迭代器的迭代。

Between container-based std:: algorithms and auto typed lambdas, using the std:: algorithms is going to become more tempting again in a version or two of C++. Even then, unless you are abstracting over the kind of algorithm you are using your lambda on, for_each is now quite questionable, because we have a first-class language feature that does what for_each does.

在基于容器的std :: algorithms和自动类型的lambda之间,使用std :: algorithms会在一两个C ++版本中再次变得更具诱惑力。即便如此,除非你在使用lambda的算法上进行抽象,否则for_each现在非常值得怀疑,因为我们有一流的语言功能可以完成for_each的功能。