воскресенье, 14 ноября 2010 г.

boost indirect_iterator

boost содержит удобную обертку indirect_iterator. Эта обертка делает дополнительное разыменование в operator*(). Это позволяет удобно работать с контейнерами, которые содержат указатели на элементы вместо самих элементов. Например,
struct test {
  int field1;
  test( int v ) : field1( v ) {}
};

typedef boost::shared_ptr<test> test_ptr_t;
typedef std::vector<test_ptr_t> test_t;
test_t test_array;

int main()
{
  test_array.push_back( test_ptr_t( new test(1) ) );
  test_array.push_back( test_ptr_t( new test(5) ) );
  test_array.push_back( test_ptr_t( new test(10) ) );

  typedef boost::indirect_iterator<test_t::const_iterator> test_const_iterator;
  using boost::make_indirect_iterator;
  for ( test_const_iterator it = make_indirect_iterator( test_array.begin() ); 
    it != make_indirect_iterator( test_array.end() ); ++it )
  {
    // пишем it->field1 вместо (*it)->field1
    std::cout << it->field1 << std::endl;
  }
}

Писанины многовато, но иногда оно того стоит. В алгоритамах indirect_iterator упрощает написание функторов:
test_const_iterator f = std::find_if(
  make_indirect_iterator( test_array.begin() ),
  make_indirect_iterator( test_array.end() ),
  boost::bind( &test::field1, _1 ) == 5 );
std::cout << f->field1 << std::endl;

Стоит отметить, что счастливые пользователи компиляторов с поддержкой нового стандарта(например, GNU C++ 4.5 или MSVC++ 2010) могут заменить все это ситаксическое безобразие лямбда функциями и написать следующее:
auto x = std::find_if(
  test_array.begin(),
  test_array.end(),
  [](test_ptr_t v) { return v->field1 == 5; } );
std::cout << (*x)->field1 << std::endl;

Комментировать в ВКонтакте