Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Парный итератор


Автор: borisbn 12.11.2011, 18:03
Всем привет. Название не очень, но попробую объяснить здесь.
Не так часто, но, в общем-то, и не редко, бывают ситуации, когда необходимо пройтись сразу по двум контейнерам. Естественно, предполагается, что они одинакового размера. Есть парочка вариантов, как это сделать:
1) В цикле for инициализировать два итератора и инкрементировать оба (так себе объяснение... лучше код)
Код

container_1_t c1;
container_2_t c2;
...
container_1_t::iterator it1 = c1.begin();
container_2_t::iterator it2 = c2.begin();
for (; it1 != c1.end(); ++it1, ++it2 ) {
  cout << (*it1) cout << (*it2);
}

2) Создать структуру из двух элементов, слить в один контейнер данные из обоих контейнеров:
Код

struct Common {
   T1 t1;
   T2 t2;
}
common_container_t< Common > common;
// слить
for ( common_container_t::iterator it = common.begin(); it != common.end(); ++it ) {
    cout << it->t1 << it->t2;
}


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

Почитывая описание BOOST_FOREACH наткнулся на такую фразу
Цитата

For example, we can use BOOST_FOREACH with: 
  STL containers 
  arrays 
  Null-terminated strings (char and wchar_t) 
  std::pair of iterators


и вот последний пункт меня заинтересовал.

Теперь, собственно, вопрос: можно ли как-то стандартным способом пройтись по двум контейнерам ?
Типа такого:
Код

container_1_t c1;
container_2_t c2;
boost::iterator_pair< container_1_t::iterator, container_2_t::iterator > iterators( c1, c2 );
for_each( iterators.begin(), iterators.end(), foo() );
...
foo( std::pair< T1, T2 > pair ) {
    cout <<  pair.first < pair.second;
}


Спасибо.

Автор: alexvs11 12.11.2011, 18:17
Код

#include <iostream>
#include <algorithm>
#include <list>

bool mypredicate (int i, int j) {
  std::cout << i << '*' << j << '=' << i * j << std::endl;
  return true;
}

int main () {
  std::vector<int> v1;
  std::list<int> v2;
  for (int i=0;i<10;++i)
  { 
     v1.push_back(i);
     v2.push_back(i*2);
  }
  
  std::mismatch(v1.begin(), v1.end(), v2.begin(), mypredicate);

  return 0;
}


наверно есть более подходящий алгоритм smile 

Автор: bsa 12.11.2011, 19:08
Цитата(borisbn @  12.11.2011,  19:03 Найти цитируемый пост)
Теперь, собственно, вопрос: можно ли как-то стандартным способом пройтись по двум контейнерам ?

std::transform.

Автор: alexvs11 12.11.2011, 19:14
bsa, да, но там есть ненужны OutputIterator

Автор: bsa 12.11.2011, 19:15
Цитата(alexvs11 @  12.11.2011,  20:14 Найти цитируемый пост)
bsa, да, но там есть ненужны OutputIterator 

никто не мешает сделать "пустой" OutputIterator

Автор: borisbn 12.11.2011, 19:44
bsa, ага. на transform заглядывался, но мне не понравилось, что нужно делать предикат (нельзя просто for), да и свой "пустой" iterator тоже лениво делать smile Ничего сложного - просто лениво.
А что, всё-таки, значит строка в доке к бусту:
Цитата
we can use BOOST_FOREACH with std::pair of iterators

Не то, что мне нужно ?

Автор: alexvs11 12.11.2011, 19:56
borisbn, а mismatch?
насчет предиката - этож stl, как иначе

по-поводу BOOST_FOREACH походу это только для std::map

Автор: boostcoder 12.11.2011, 20:04
Цитата(borisbn @  12.11.2011,  19:44 Найти цитируемый пост)
А что, всё-таки, значит строка в доке к бусту

это поддержка спецификации boost.range, ибо там один объект хранит два итератора, т.е. range.
Код

#include <iostream>
#include <string>
#include <utility>
#include <boost/foreach.hpp>

int main() {
   std::string s1("123456");
   
   BOOST_FOREACH(char ch, std::make_pair(s1.begin(), s1.end())) {
      std::cout << ch;
   }
}

http://liveworkspace.org/code/51c35636811766545509eec8fff40ac4

Добавлено через 1 минуту и 46 секунд
Цитата(alexvs11 @  12.11.2011,  19:56 Найти цитируемый пост)
BOOST_FOREACH походу это только для std::map

приведи пример пожалуйста.

Автор: alexvs11 12.11.2011, 20:13
Цитата(boostcoder @  12.11.2011,  20:04 Найти цитируемый пост)
приведи пример пожалуйста. 

вы видимо ответили на вопрос
я чисто по отрывкам из интернетов сделал вывод

Автор: boostcoder 12.11.2011, 20:26
borisbn, а вот ответ на твой вопрос:
Код

#include <iostream>
#include <string>
#include <boost/range/algorithm_ext/for_each.hpp>

int main() {
   std::string s1("123456");
   std::string s2(s1);
   
   boost::for_each(s1, s2,
      [](char c1, char c2) {
         std::cout << "c1: " << c1 << std::endl;
         std::cout << "c2: " << c2 << std::endl;
      }
   );
}

http://liveworkspace.org/code/0d3632e0846e791b9482af54dbc28e52

Автор: borisbn 12.11.2011, 22:19
Цитата(boostcoder @  12.11.2011,  20:04 Найти цитируемый пост)
BOOST_FOREACH(char ch, std::make_pair(s1.begin(), s1.end()))

ясно. не то.

Цитата(boostcoder @  12.11.2011,  20:26 Найти цитируемый пост)
boost::for_each(s1, s2,

то. типа "sugar" version of transform...
ИМХО пример был бы лучше такой (разные контейнеры)
Код

   std::vector< int > s1 = { 1, 2, 3, 4, 5 };
   std::vector< std::string > s2 = { "qwe", "rty", "asd", "fgh", "zxc" };
   
   boost::for_each(s1, s2,
      []( int c1, const std::string & c2 ) {
         std::cout << "c1: " << c1 << std::endl;
         std::cout << "c2: " << c2 << std::endl;
      }
   );


boostcoder, респект и спасибо.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)