#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
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
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
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
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的功能。