Подтвердить что ты не робот

Как использовать BOOST_FOREACH с boost:: ptr_map?

Как я могу эффективно использовать BOOST_FOREACH (число символов/читаемость) с boost:: ptr_map?

Кристо продемонстрировал в своем ответе , что можно использовать 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;
}
4b9b3361

Ответ 1

В качестве контейнеров стиля 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 для контейнера делает код намного легче писать.

Кроме того, вы должны стараться избегать использования содержимого пространств имен detail в boost, это соглашение ускорения, в котором они содержат сведения о реализации.

Ответ 2

Сегодня я столкнулся с одной и той же проблемой. К сожалению, предложение Дэниела не будет работать с постоянной ссылкой на карту. В моем случае 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>.

Ответ 3

Сохраните ввод и улучшите читаемость с помощью кортежей:

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

Ответ 4

Этот примерный код, скомпилированный для меня с 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

Я использую этот шаблон homebrew, который добавляет тип итерации, который может обрабатываться 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 и бар - два из ваших любимых типов;)

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 или non-const), но на константе карты! Итак, следующее приведет к ошибке...

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

Weird! не так ли?

Самое замечательное для меня, что из всех этих решений, которые были предложены здесь, это первый, который правильно обрабатывается раскраской синтаксиса Eclipse CDT (при использовании атрибута раскраски синтаксиса "Код/проблема" ).

Ответ 6

Он должен скомпилироваться без ссылки:

BOOST_FOREACH (IntTpair p, mymap)

Я думаю, проблема в том, что карты фактически не хранят объекты как пары, а как древовидную структуру с первым элементом в качестве ключа, поэтому BOOST_FOREACH не может получить ссылку на пару, но может создать временную копию один.

Ответ 7

использование:: 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

В конце я пошел за объявлением переменной итерации перед циклом.

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

Но действительно, должен быть более простой способ. (Вместо этого используйте D?)

Ответ 9

Вы можете попробовать этот uber-cool способ перебора карт, 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

Я не уверен, что он будет работать с параметром шаблона, но, возможно, вы использовали это только для абстракции.