C++ 在地图元素上使用 for_each
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2850312/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Use of for_each on map elements
提问by Antonio Pérez
I have a map where I'd like to perform a call on every data type object member function. I yet know how to do this on any sequence but, is it possible to do it on an associative container?
我有一张地图,我想在其中对每个数据类型对象成员函数执行调用。我还知道如何在任何序列上执行此操作,但是是否可以在关联容器上执行此操作?
The closest answer I could find was this: Boost.Bind to access std::map elements in std::for_each. But I cannot use boost in my project so, is there an STL alternative that I'm missing to boost::bind?
我能找到的最接近的答案是:Boost.Bind 访问 std::for_each 中的 std::map 元素。但是我不能在我的项目中使用 boost,所以我缺少 boost::bind 的 STL 替代方案吗?
If not possible, I thought on creating a temporary sequence for pointers to the data objects and then, call for_each on it, something like this:
如果不可能,我想为指向数据对象的指针创建一个临时序列,然后在其上调用 for_each,如下所示:
class MyClass
{
public:
void Method() const;
}
std::map<int, MyClass> Map;
//...
std::vector<MyClass*> Vector;
std::transform(Map.begin(), Map.end(), std::back_inserter(Vector), std::mem_fun_ref(&std::map<int, MyClass>::value_type::second));
std::for_each(Vector.begin(), Vector.end(), std::mem_fun(&MyClass::Method));
It looks too obfuscated and I don't really like it. Any suggestions?
它看起来太模糊了,我真的不喜欢它。有什么建议?
回答by Sebastian
C++11 allows you to do:
C++11 允许您执行以下操作:
for (const auto& kv : myMap) {
std::cout << kv.first << " has value " << kv.second << std::endl;
}
C++17 allows you to do:
C++17 允许您执行以下操作:
for (const auto& [key, value] : myMap) {
std::cout << key << " has value " << value << std::endl;
}
using structured binding.
使用结构化绑定。
UPDATE:
更新:
const auto is safer if you don't want to modify the map.
如果您不想修改地图,则 const auto 更安全。
回答by ereOn
You can iterate through a std::map
object. Each iterator will point to a std::pair<const T,S>
where T
and S
are the same types you specified on your map
.
您可以遍历一个std::map
对象。每个迭代器将指向一个std::pair<const T,S>
whereT
并且S
是您在map
.
Here this would be:
这将是:
for (std::map<int, MyClass>::iterator it = Map.begin(); it != Map.end(); ++it)
{
it->second.Method();
}
If you still want to use std::for_each
, pass a function that takes a std::pair<const int, MyClass>&
as an argument instead.
如果您仍想使用std::for_each
,请传递一个将 astd::pair<const int, MyClass>&
作为参数的函数。
Example:
例子:
void CallMyMethod(std::pair<const int, MyClass>& pair) // could be a class static method as well
{
pair.second.Method();
}
And pass it to std::for_each
:
并将其传递给std::for_each
:
std::for_each(Map.begin(), Map.end(), CallMyMethod);
回答by Christian Rapp
C++14 brings generic lambdas. Meaning we can use std::for_each very easily:
C++14 带来了泛型 lambda。这意味着我们可以很容易地使用 std::for_each :
std::map<int, int> myMap{{1, 2}, {3, 4}, {5, 6}, {7, 8}};
std::for_each(myMap.begin(), myMap.end(), [](const auto &myMapPair) {
std::cout << "first " << myMapPair.first << " second "
<< myMapPair.second << std::endl;
});
I think std::for_each is sometimes better suited than a simple range based for loop. For example when you only want to loop through a subset of a map.
我认为 std::for_each 有时比基于简单范围的 for 循环更适合。例如,当您只想遍历地图的一个子集时。
回答by bobah
How about a plain C++? (example fixed according to the note by @Noah Roberts)
一个普通的 C++ 怎么样?(根据@Noah Roberts 的说明修复的示例)
for(std::map<int, MyClass>::iterator itr = Map.begin(), itr_end = Map.end(); itr != itr_end; ++itr) {
itr->second.Method();
}
回答by David Joyner
It's unfortunate that you don't have Boost however if your STL implementation has the extensions then you can compose mem_fun_ref and select2nd to create a single functor suitable for use with for_each. The code would look something like this:
不幸的是,你没有 Boost 但是如果你的 STL 实现有扩展,那么你可以组合 mem_fun_ref 和 select2nd 来创建一个适合与 for_each 一起使用的函子。代码看起来像这样:
#include <algorithm>
#include <map>
#include <ext/functional> // GNU-specific extension for functor classes missing from standard STL
using namespace __gnu_cxx; // for compose1 and select2nd
class MyClass
{
public:
void Method() const;
};
std::map<int, MyClass> Map;
int main(void)
{
std::for_each(Map.begin(), Map.end(), compose1(std::mem_fun_ref(&MyClass::Method), select2nd<std::map<int, MyClass>::value_type>()));
}
Note that if you don't have access to compose1 (or the unary_compose template) and select2nd, they are fairly easy to write.
请注意,如果您无权访问 compose1(或 unary_compose 模板)和 select2nd,则它们很容易编写。
回答by Offirmo
For fellow programmers who stumble upon this question from google, there is a good way using boost.
对于从 google 偶然发现这个问题的程序员同行,有一个使用 boost 的好方法。
Explained here : Is it possible to use boost::foreach with std::map?
在这里解释:是否可以将 boost::foreach 与 std::map 一起使用?
Real example for your convenience :
为您提供方便的真实示例:
// typedef in include, given here for info :
typedef std::map<std::string, std::string> Wt::WEnvironment::CookieMap
Wt::WEnvironment::CookieMap cookie_map = environment.cookies();
BOOST_FOREACH( const Wt::WEnvironment::CookieMap::value_type &cookie, cookie_map )
{
std::cout << "cookie : " << cookie.first << " = " << cookie.second << endl;
}
enjoy.
请享用。
回答by moswald
I wrote this awhile back to do just what you're looking for.
我写了一段时间回来做你正在寻找的东西。
namespace STLHelpers
{
//
// iterator helper type for iterating through the *values* of key/value collections
//
/////////////////////////////////////////////
template<typename _traits>
struct _value_iterator
{
explicit _value_iterator(typename _traits::iterator_type _it)
: it(_it)
{
}
_value_iterator(const _value_iterator &_other)
: it(_other.it)
{
}
friend bool operator==(const _value_iterator &lhs, const _value_iterator &rhs)
{
return lhs.it == rhs.it;
}
friend bool operator!=(const _value_iterator &lhs, const _value_iterator &rhs)
{
return !(lhs == rhs);
}
_value_iterator &operator++()
{
++it;
return *this;
}
_value_iterator operator++(int)
{
_value_iterator t(*this);
++*this;
return t;
}
typename _traits::value_type &operator->()
{
return **this;
}
typename _traits::value_type &operator*()
{
return it->second;
}
typename _traits::iterator_type it;
};
template<typename _tyMap>
struct _map_iterator_traits
{
typedef typename _tyMap::iterator iterator_type;
typedef typename _tyMap::mapped_type value_type;
};
template<typename _tyMap>
struct _const_map_iterator_traits
{
typedef typename _tyMap::const_iterator iterator_type;
typedef const typename _tyMap::mapped_type value_type;
};
}
回答by vodkhang
回答by a1ex07
Will it work for you ?
它对你有用吗?
class MyClass;
typedef std::pair<int,MyClass> MyPair;
class MyClass
{
private:
void foo() const{};
public:
static void Method(MyPair const& p)
{
//......
p.second.foo();
};
};
// ...
std::map<int, MyClass> Map;
//.....
std::for_each(Map.begin(), Map.end(), (&MyClass::Method));
回答by aJ.
Just an example:
只是一个例子:
template <class key, class value>
class insertIntoVec
{
public:
insertIntoVec(std::vector<value>& vec_in):m_vec(vec_in)
{}
void operator () (const std::pair<key, value>& rhs)
{
m_vec.push_back(rhs.second);
}
private:
std::vector<value>& m_vec;
};
int main()
{
std::map<int, std::string> aMap;
aMap[1] = "test1";
aMap[2] = "test2";
aMap[3] = "test3";
aMap[4] = "test4";
std::vector<std::string> aVec;
aVec.reserve(aMap.size());
std::for_each(aMap.begin(), aMap.end(),
insertIntoVec<int, std::string>(aVec)
);
}
}