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

时间:2023-01-14 14:00:50

How can I use BOOST_FOREACH efficiently (number-of-character/readability-wise) with a boost::ptr_map?

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

Kristo demonstrated in his answer that it is possible to use BOOST_FOREACH with a ptr_map, but it does not really save me any typing (or makes my code really more readable) than iterating over the ptr_map with an iterator:

Kristo在他的回答中证明了可以将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()
}

The following code is somewhere along the lines what I wish for. It follows the standard way on how to use BOOST_FOREACH with a std::map. Unfortunately this does not compile:

以下代码是我想要的代码。它遵循如何将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 个解决方案

#1


As STL style containers, the pointer containers have a value_type typedef that you can use:

作为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)
    {
    }
}

I find that using a typedef for the container makes the code a lot easier to write.

我发现对容器使用typedef会使代码更容易编写。

Also, you should try to avoid using the contents of detail namespaces in boost, it's a boost convention that they contain implementation details.

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

#2


I just ran into the same problem today. Unfortunately, Daniel's suggestion will not work with a constant reference to a map. In my case, the ptr_map was a member of a class, and I wanted to loop through it in a const member function. Borrowing Daniel's example, this is what I had to do in my case:

我今天遇到了同样的问题。不幸的是,丹尼尔的建议不适用于对地图的不断引用。在我的例子中,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)
    {
    }
}

It seems that int_map::const_iterator::value_type is equivalent to boost::ptr_container_detail::ref_pair<int, const int* const>.

似乎int_map :: const_iterator :: value_type等效于boost :: ptr_container_detail :: ref_pair ,const>

#3


Save yourself the typing and improve readability by using tuples:

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

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

#4


This example code compiled for me with g++ 4.1.2:

使用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;
}

#5


I use this homebrew template which adds an iteration type which can be handled by BOOST_FOREACH

我使用这个自制模板添加了一个迭代类型,可以由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;
  };
} 

Let's assume that foo and bar are two of your favorite types ;)

让我们假设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
  }
}

or

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

Which one you have to use doesn't seem to depend on the way you use it in the loop (const or non-const) but on the map's constness!! So the following will end up in an error...

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

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

Weird! isn't it?

奇怪的!不是吗?

The greatest thing to me is that of all this solutions which were suggested here, this is the first one which is handled correctly by the Eclipse CDT syntax coloring (when using the 'Code/Problem' syntax coloring attribute).

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

#6


It should compile without the reference:

它应该编译而不参考:

BOOST_FOREACH (IntTpair p, mymap)

I think the problem is that maps do not actually store objects as pairs, but as a tree structure with the first element as the key, so BOOST_FOREACH can't get a reference to a pair but it can create a temporary copy of one.

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

#7


using ::value_type won't let you const-iterate through the container. I use iterator reference types

使用:: 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 );

#8


In the end, I went for declaring the iteration variable before the loop.

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

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

But indeed, there ought to be a simpler way. (Use D instead?)

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

#9


You might try this uber-cool way to iterate over maps, ptr or otherwise: https://svn.boost.org/trac/boost/attachment/ticket/3469/foreach_field.hpp

您可以尝试这种超级酷的方式迭代地图,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

I'm not sure it will work with a template parameter, but maybe you used that just for abstraction.

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

#1


As STL style containers, the pointer containers have a value_type typedef that you can use:

作为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)
    {
    }
}

I find that using a typedef for the container makes the code a lot easier to write.

我发现对容器使用typedef会使代码更容易编写。

Also, you should try to avoid using the contents of detail namespaces in boost, it's a boost convention that they contain implementation details.

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

#2


I just ran into the same problem today. Unfortunately, Daniel's suggestion will not work with a constant reference to a map. In my case, the ptr_map was a member of a class, and I wanted to loop through it in a const member function. Borrowing Daniel's example, this is what I had to do in my case:

我今天遇到了同样的问题。不幸的是,丹尼尔的建议不适用于对地图的不断引用。在我的例子中,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)
    {
    }
}

It seems that int_map::const_iterator::value_type is equivalent to boost::ptr_container_detail::ref_pair<int, const int* const>.

似乎int_map :: const_iterator :: value_type等效于boost :: ptr_container_detail :: ref_pair ,const>

#3


Save yourself the typing and improve readability by using tuples:

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

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

#4


This example code compiled for me with g++ 4.1.2:

使用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;
}

#5


I use this homebrew template which adds an iteration type which can be handled by BOOST_FOREACH

我使用这个自制模板添加了一个迭代类型,可以由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;
  };
} 

Let's assume that foo and bar are two of your favorite types ;)

让我们假设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
  }
}

or

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

Which one you have to use doesn't seem to depend on the way you use it in the loop (const or non-const) but on the map's constness!! So the following will end up in an error...

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

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

Weird! isn't it?

奇怪的!不是吗?

The greatest thing to me is that of all this solutions which were suggested here, this is the first one which is handled correctly by the Eclipse CDT syntax coloring (when using the 'Code/Problem' syntax coloring attribute).

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

#6


It should compile without the reference:

它应该编译而不参考:

BOOST_FOREACH (IntTpair p, mymap)

I think the problem is that maps do not actually store objects as pairs, but as a tree structure with the first element as the key, so BOOST_FOREACH can't get a reference to a pair but it can create a temporary copy of one.

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

#7


using ::value_type won't let you const-iterate through the container. I use iterator reference types

使用:: 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 );

#8


In the end, I went for declaring the iteration variable before the loop.

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

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

But indeed, there ought to be a simpler way. (Use D instead?)

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

#9


You might try this uber-cool way to iterate over maps, ptr or otherwise: https://svn.boost.org/trac/boost/attachment/ticket/3469/foreach_field.hpp

您可以尝试这种超级酷的方式迭代地图,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

I'm not sure it will work with a template parameter, but maybe you used that just for abstraction.

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