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