如何将BOOST_FOREACH与boost :: ptr_map一起使用?

时间:2009-01-20 14:26:55

标签: c++ boost

如何使用boost :: ptr_map有效地使用BOOST_FOREACH(字符数/可读性)?

Kristo在他的answer中演示了可以将BOOST_FOREACH与ptr_map一起使用,但它并没有真正省去任何打字(或使我的代码更具可读性),而不是使用迭代器迭代ptr_map:

typedef boost::ptr_container_detail::ref_pair<int, int* const> IntPair;
BOOST_FOREACH(IntPair p, mymap) {
    int i = p.first;
}

// vs.

boost::ptr_map<int, T>::iterator it;
for (it = mymap.begin(); it != mymap.end(); ++it) {
    // doSomething()
}

下面的代码就像我希望的那样。它遵循如何将BOOST_FOREACH与std :: map一起使用的标准方法。不幸的是,这不编译:

boost::ptr_map<int, T> mymap;
// insert something into mymap
// ...

typedef pair<int, T> IntTpair;
BOOST_FOREACH (IntTpair &p, mymap) {
    int i = p.first;
}

9 个答案:

答案 0 :(得分:16)

作为STL样式容器,指针容器具有可以使用的value_type typedef:

#include <boost/ptr_container/ptr_map.hpp>
#include <boost/foreach.hpp>

int main()
{
    typedef boost::ptr_map<int, int> int_map;
    int_map mymap;

    BOOST_FOREACH(int_map::value_type p, mymap)
    {
    }
}

我发现使用容器的typedef可以使代码更容易编写。

此外,您应该尽量避免在boost中使用detail命名空间的内容,这是一个包含实现细节的提升约定。

答案 1 :(得分:8)

我今天遇到了同样的问题。不幸的是,丹尼尔的建议不适用于对地图的不断引用。在我的例子中,ptr_map是一个类的成员,我想在const成员函数中循环它。借用丹尼尔的例子,这就是我在我的案例中必须做的事情:

#include "boost/ptr_container/ptr_map.hpp"
#include "boost/foreach.hpp"

int main()
{
    typedef boost::ptr_map<int, int> int_map;
    int_map mymap;
    const int_map& mymap_const_ref(mymap);

    BOOST_FOREACH(int_map::const_iterator::value_type p, mymap_const_ref)
    {
    }
}

似乎int_map::const_iterator::value_type等同于boost::ptr_container_detail::ref_pair<int, const int* const>

答案 2 :(得分:6)

使用元组保存自己的输入并提高可读性:

boost::ptr_map<int, T> mymap;
int key;
T * value;
BOOST_FOREACH(boost::tie(key, value), mymap)
{
    ...
}

答案 3 :(得分:1)

这个用g ++ 4.1.2为我编译的示例代码:

#include "boost/ptr_container/ptr_map.hpp"
#include "boost/foreach.hpp"

int main()
{
    boost::ptr_map<int, int> mymap;

    typedef boost::ptr_container_detail::ref_pair<int, int* const> IntPair;
    BOOST_FOREACH(IntPair p, mymap)
    {
        int i = p.first;
    }

    return 0;
}

答案 4 :(得分:1)

我使用这个自制模板添加了一个迭代类型,可以通过 BOOST_FOREACH

来处理
namspace homebrew
{
  template
  <
    class Key,
    class T,
    class Compare        = std::less<Key>,
    class CloneAllocator = boost::heap_clone_allocator,
    class Allocator      = std::allocator< std::pair<const Key,void*> >
  >
  class ptr_map :
    public boost::ptr_map<Key,T,Compare,CloneAllocator,Allocator>
  {
  public:
    typedef boost::ptr_container_detail::ref_pair<Key,const T* const> const_ref;
    typedef boost::ptr_container_detail::ref_pair<Key,T* const> ref;
  };
} 

我们假设 foo bar 是您最喜欢的两种类型;)

typedef homebrew::ptr_map<foo,bar> Map;
int f( const Map& m )
{
  BOOST_FOREACH(Map::const_ref v, m)
  {
    v.first;  // foo
    v.second; // const bar* const
  }
}

int f( Map& m )
{
  BOOST_FOREACH(Map::ref v, m)
  {
    v.first;  // foo
    v.second; // bar* const
  }
}

你必须使用哪一个似乎并不依赖于你在循环中使用它的方式(const或非const),而是依赖于地图的constness!所以以下内容最终会出错...

int f( Map& m )
{
  BOOST_FOREACH(Map::const_ref v, m)  // can't use const_ref because m isn't const
  {
    ...
  }
}

奇怪!不是吗?

对我而言,最重要的是在这里提出的所有这些解决方案中,这是第一个通过Eclipse CDT语法着色正确处理的解决方案(当使用'Code / Problem'语法着色属性时)。

答案 5 :(得分:0)

它应该在没有引用的情况下编译:

BOOST_FOREACH (IntTpair p, mymap)

我认为问题在于地图实际上并不将对象存储为对,而是以第一个元素作为键的树结构,因此BOOST_FOREACH无法获得对对的引用,但它可以创建临时副本之一。

答案 6 :(得分:0)

使用:: value_type将不允许您遍历容器。我使用迭代器引用类型

typedef boost::ptr_map< myKey, myPtrType > MyMap;
MyMap m;
BOOST_FOREACH( MyMap::iterator::reference it, m )
  do_something( it.second );
BOOST_FOREACH( MyMap::const_iterator::reference it, m )
  do_something_const( it.second );

答案 7 :(得分:0)

最后,我在循环之前声明了迭代变量。

std::pair<std::string, TrailStep*> step;
BOOST_FOREACH(step, m_steps)
{
    SAFE_DELETE(step.second);
}

但实际上,应该采用更简单的方法。 (改用D?)

答案 8 :(得分:0)

您可以尝试这种超级酷的方式来迭代地图,ptr或其他方式: https://svn.boost.org/trac/boost/attachment/ticket/3469/foreach_field.hpp

// no typedef needed
BOOST_FOREACH_FIELD((int i)(const T& t), mymap)
   // do something with i or t instead of first/second

我不确定它是否适用于模板参数,但也许您只是用于抽象。