Как использовать BOOST_FOREACH с boost :: ptr_map? - PullRequest
12 голосов
/ 20 января 2009

Как я могу эффективно использовать 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;
}

Ответы [ 9 ]

16 голосов
/ 26 января 2009

Как контейнеры в стиле 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, это соглашение о повышении, которое содержит детали реализации.

8 голосов
/ 07 января 2010

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

6 голосов
/ 24 января 2012

Сохраните набор текста и улучшите читабельность, используя кортежи:

boost::ptr_map<int, T> mymap;
int key;
T * value;
BOOST_FOREACH(boost::tie(key, value), mymap)
{
    ...
}
1 голос
/ 17 мая 2011

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

То, что вы должны использовать, похоже, зависит не от того, как вы используете его в цикле (константном или неконстантном), а от константности карты !! Таким образом, следующее приведет к ошибке ...

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

Weird! не так ли?

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

1 голос
/ 20 января 2009

Этот пример кода скомпилирован для меня с 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;
}
0 голосов
/ 08 сентября 2011

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

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

0 голосов
/ 11 апреля 2011

В итоге я объявил переменную итерации перед циклом.

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

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

0 голосов
/ 15 октября 2010

использование :: 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 );
0 голосов
/ 20 января 2009

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

BOOST_FOREACH (IntTpair p, mymap)

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...