[英]Easy way to iterate std::map<…>?
我有一个类型类似于的变量:
map<bool, map<string, pair<string, int> > > items;
我将其传递给不同的功能。
有没有一种不那么乏味的方式让我迭代它然后说
for (map<bool, map<string, pair<string, int> > >::iterator p = items.begin();
p != items.end(); p++)
...
每次? (即我可以用宏或模板或其他东西以某种方式省略类型名称吗?手动typedef
不算数。)
我正在使用 Visual C++ 2008。
您可以使用BOOST_FOREACH
。 为了清楚起见,您必须使用 typedef:
typedef std::map<std::string, std::pair<std::string, int> > inner_map;
typedef std::pair<bool, inner_map> map_entry;
BOOST_FOREACH(map_entry& p, items)
{
...
}
不过,我更喜欢普通的typedef
和 for 循环。 我看到typedef
的方式与看到变量赋值的方式相同:
typedef std::map<std::string, std::pair<std::string, int> > inner_map;
typedef std::map<bool, inner_map>::iterator map_iterator;
for (map_iterator i = items.begin(); i != items.end(); ++i)
{
...
}
这些 typedef 也可以是私有成员。 这种编码风格更加清晰,因为您一眼就可以看到所涉及的类型。
或者,如果您准备编写仿函数,则可以使用普通的std::for_each
。 我不太喜欢标准 C++ 中的这个,因为循环体不再是本地的(但是在某些情况下这可能是一个优势):
struct some_functor
{
template <typename K, typename V>
void operator()(std::pair<K, V>& item)
{
// In the context below, K is bool and
// V is map<string, pair<string, int> >
}
};
然后稍后
std::for_each(items.begin(), items.end(), some_functor());
如果您升级到 VS2010,您有其他选择: auto
和std::for_each
与 lambda(我更喜欢)。 从技术上讲,使用 C++0x,您还可以使用基于范围的 for 循环(在 VS2010 中不可用)。
总而言之,我会这样做:
class meaningful_data
{
typedef std::map<std::string, std::pair<std::string, int> > inner_map;
std::map<bool, inner_map> items;
public:
typedef std::pair<bool, inner_map> value_type;
typedef std::map<bool, inner_map>::iterator iterator;
typedef std::map<bool, inner_map>::const_iterator const_iterator;
iterator begin() { return items.begin(); }
const_iterator begin() const { return items.begin(); }
iterator end() { return items.end(); }
const_iterator end() const { return items.end(); }
// Add some interface here (as small as possible)
};
并像这样迭代:
for (meaningful_data::iterator i = d.begin(); i != d.end(); ++i)
{
...
}
或者
BOOST_FOREACH(meaningful_data::value_type& i, d)
{
...
}
您可能想要封装这样一个复杂的类型,至少使用一些 typedef(如果inner_map
类型应该是公共的,您不必强制使用完整的 class)。
我建议使用typedef
,这可能是一种说“不,你不能”的方式;)
否则,如果您要切换到支持 C++0x 中定义的auto
的编译器,您可以说:
for (auto p = items.begin(); p != items.end(); ++p) // ...
(哦,对了,我也推荐++p
避免复制迭代器)
您可以使用标准的 for_each 算法:
#include <algorithm>
struct your_functor {
template<typename T>
void operator()(T const &item) {
// Your loop body here.
}
}
std::for_each(items.begin(), items.end(), your_functor());
您可以使用BOOST_AUTO
您可以编写自己的算法 function。
template<class C>
void do_what_I_want_to_do(C& c)
{
for (C::iterator i = c.begin(); i != c.end(); ++c)
{
// do something
}
}
do_what_I_want_to_do(items);
这对你来说可能是也可能不是改进。
Qt 提供了自己的 foreach 实现,所以我只是为 std::map 重新设计了它——基本上只是一个简单的修改(->秒)。 在 MSVC 和 gcc 上测试。
struct ForeachBaseBase {};
template <typename T1, typename T2>
class ForeachBase: public ForeachBaseBase
{
public:
inline ForeachBase(const std::map<T1,T2>& t): c(t), brk(0), i(c.begin()), e(c.end()){}
const std::map<T1,T2> c;
mutable int brk;
mutable typename std::map<T1,T2>::const_iterator i, e;
inline bool condition() const { return (!brk++ && i != e);}
};
template <typename T1, typename T2> inline std::map<T1,T2> *pMForeachPointer(const std::map<T1,T2> &) { return 0; }
template <typename T1, typename T2> inline ForeachBase<T1,T2> pMForeachBaseNew(const std::map<T1,T2>& t)
{ return ForeachBase<T1,T2>(t); }
template <typename T1, typename T2>
inline const ForeachBase<T1,T2> *pMForeachBase(const ForeachBaseBase *base, const std::map<T1,T2> *)
{ return static_cast<const ForeachBase<T1,T2> *>(base); }
#if defined(Q_CC_MIPS)
/*
Proper for-scoping in MIPSpro CC
*/
# define MAP_FOREACH(variable,container) \
if(0){}else \
for (const ForeachBaseBase &_container_ = pMForeachBaseNew(container); \
pMForeachBase(&_container_, true ? 0 : pMForeachPointer(container))->condition(); \
++pMForeachBase(&_container_, true ? 0 : pMForeachPointer(container))->i) \
for (variable = pMForeachBase(&_container_, true ? 0 : pMForeachPointer(container))->i->second; \
pMForeachBase(&_container_, true ? 0 : pMForeachPointer(container))->brk; \
--pMForeachBase(&_container_, true ? 0 : pMForeachPointer(container))->brk)
#elif defined(Q_CC_DIAB)
// VxWorks DIAB generates unresolvable symbols, if container is a function call
# define MAP_FOREACH(variable,container) \
if(0){}else \
for (const ForeachBaseBase &_container_ = pMForeachBaseNew(container); \
pMForeachBase(&_container_, (__typeof__(container) *) 0)->condition(); \
++pMForeachBase(&_container_, (__typeof__(container) *) 0)->i) \
for (variable = pMForeachBase(&_container_, (__typeof__(container) *) 0)->i->second; \
pMForeachBase(&_container_, (__typeof__(container) *) 0)->brk; \
--pMForeachBase(&_container_, (__typeof__(container) *) 0)->brk)
#else
# define MAP_FOREACH(variable, container) \
for (const ForeachBaseBase &_container_ = pMForeachBaseNew(container); \
pMForeachBase(&_container_, true ? 0 : pMForeachPointer(container))->condition(); \
++pMForeachBase(&_container_, true ? 0 : pMForeachPointer(container))->i) \
for (variable = pMForeachBase(&_container_, true ? 0 : pMForeachPointer(container))->i->second; \
pMForeachBase(&_container_, true ? 0 : pMForeachPointer(container))->brk; \
--pMForeachBase(&_container_, true ? 0 : pMForeachPointer(container))->brk)
#endif // MSVC6 || MIPSpro
#define mforeach MAP_FOREACH
当然,使用 typedef:
typedef std::map<std::string, std::pair<std::string, int> > Item;
typedef Item::const_iterator ItemCItr;
typedef std::map<bool, Item> ItemMap;
typedef ItemMap::const_iterator ItemMapItr;
for (ItemMapItr it = m.begin(), end = m.end(); it != end; ++it)
{
const Item & item = it->second;
for (ItemItr jt = item.begin(), jend = item.end(); jt != jend; ++jt)
{
/* ... */
}
}
在看到所有“不,你不能这样做”的答案后,我花了一些时间试图找到至少部分解决方法。
这个版本几乎可以工作,但需要注意的是,对迭代器的每个引用也需要对容器的引用。 实际使用它可能不是一个好主意(因为堆分配和其他事情),但我想我还是会分享它:
#include <map>
#include <iostream>
using namespace std;
template<typename T>
bool _end(T& src, void *iterator = NULL)
{ return static_cast<typename T::iterator>(iterator) < src.end(); }
template<typename T>
struct _IterateHelper
{
typename T::iterator *pIterator;
_IterateHelper(T& dummy, void *&p)
{ this->pIterator = static_cast<typename T::iterator *>(p); }
~_IterateHelper() { delete pIterator; }
};
template<typename T>
_IterateHelper<T> _iterateHelper(T& dummy, void *&p)
{ return _IterateHelper<T>(dummy, p); }
template<typename T>
bool _iterate(T& container, void *&iterator)
{
typename T::iterator *&p =
reinterpret_cast<typename T::iterator *&>(iterator);
if (iterator == NULL) { p = new typename T::iterator(container.begin()); }
else { ++*p; }
return *p != container.end();
}
template<typename T>
typename T::iterator & I(T& container, void *&pIterator)
{ return *static_cast<typename T::iterator *>(pIterator); }
#define FOR_EACH(state, container) \
void *state = NULL; \
for (_iterateHelper(container, state); _iterate(container, state); )
int main()
{
map<string, string> m;
items["a"] = "b";
items["1"] = "2";
FOR_EACH(p, items)
cout << I(items, p)->first << ": " << I(items, p)->second << endl;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.