Как использовать BOOST_FOREACH с двумя std :: maps? - PullRequest
2 голосов
/ 21 апреля 2009

У меня есть код, который выглядит по существу так:

std::map<int, int> map1, map2;
BOOST_FOREACH(int i, map1)
{
    // do steps 1-5 here...
}
BOOST_FOREACH(int i, map2)
{
    // do steps 1-5 (identical to above) here...
}

Есть ли способ объединить карты, чтобы исключить повторяющийся код во втором цикле? Или способ расширить BOOST_FOREACH для перебора двух разных карт за один раз? Очевидно, я не хочу увеличивать временную сложность программы (иначе я мог бы просто создать новую карту и вставить в нее map1 и map2). У меня такое чувство, что я здесь упускаю что-то рудиментарное.

Ответы [ 6 ]

9 голосов
/ 21 апреля 2009

Вы можете определить функцию:

typedef std::map<int, int> IntMap;

void doStuffWithInt(IntMap::value_type &i)
{
  // steps 1 to 5
}

BOOST_FOREACH(IntMap::value_type &i, map1)
  doStuffWithInt(i);
BOOST_FOREACH(IntMap::value_type &i, map2)
  doStuffWithInt(i);

Хотя в этом случае может быть еще проще использовать std::for_each:

for_each(map1.begin(), map1.end(), doStuffWithInt);
for_each(map2.begin(), map2.end(), doStuffWithInt);
3 голосов
/ 21 апреля 2009

Идея состоит в том, чтобы написать специальный тип итераторов для виртуального объединения двух контейнеров, что касается BOOST_FOREACH. Обратите внимание, что я не создаю новый контейнер из двух существующих. Я просто прыгаю с конца первого контейнера end () на итератор begin () второго контейнера. Я не пытался написать реальный класс merged_iterator, но, хотя он может быть немного длинным, технически это не сложно. Я на самом деле удивлен, что не нашел что-то подобное с помощью Google. Я долго не смотрел!

template<typename Container>
boost::iterator_range<
  merged_iterator<Container::iterator>
  >
concat_containers( Container& c1, Container& c2 )
{
  typedef merged_iterator<typename Container::iterator> MergedIterator;
  typedef boost::iterator_range<MergedIterator> IteratorRange;
  return IteratorRange(
    MergeIterator( c1.begin(), c1.end(), c2.begin(), c2.end() ),
    MergeIterator( c2.end(), c1.end(), c2.begin(), c2.end() ) );
}

// Now use a bit of magic to define merged_iterator<...>
// And you'll be able to write

BOOST_FOREACH( std::pair<int, int> i, concat_containers( map1, map2 ) )
{
// Do whatever you want here
}
2 голосов
/ 21 апреля 2009

В дополнение к решению 1800, которое я бы порекомендовал, есть также различные хакерские решения:

for (int stage = 0; stage < 2; stage++) {
    BOOST_FOREACH(int i, stage == 0 ? map1 : map2) {
        ...
    }
}

typedef std::map<int, int> intmap;
std::vector<intmap *> v;
v.push_back(&map1);
v.push_back(&map2);
BOOST_FOREACH(intmap *m, v) {
    BOOST_FOREACH(int i, *m) {
        ...
    }
}

Примечание: когда я вижу, как коллеги пишут подобный код, иногда меня одолевает непреодолимое желание задушить их. Используйте на свой страх и риск.

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

Самый простой способ такой:

std::map<int, int> map1, map2;
int key, value;
BOOST_FOREACH(boost::tie(key, value), boost::join(map1, map2))
{
    // do steps 1-5 here...
}

И не волнуйтесь, эти запятые не запутают препроцессор из-за скобок.

0 голосов
/ 28 октября 2011

Это объяснено здесь .

Вы можете сделать это:

std::map<int,int> m;
typedef std::pair<int,int> pair_t;
BOOST_FOREACH(pair_t p, m)
0 голосов
/ 02 марта 2010

Из макушки головы я бы попробовал

std::map<int, int> map1, map2;
std::map<int, int>& maps = { map1, map2 }
BOOST_FOREACH(std::map<int, int> map, maps)
  BOOST_FOREACH(int i, map)
  {
      // do steps 1-5 here...
  }
...