четверг, 25 ноября 2010 г.

strong typedef

Известно, что typedef не создает новый тип, а просто вводит алиас для существующего типа. Т.е., например, объявив
typedef int myint_t;
нельзя перегрузить функцию для myint_t, так как типы неразличимы для компилятора:
void f( int );
void f( myint_t ); // error
Если мы хотим эти типы различать, то решение состоит в том, чтобы создать структуру myint_t вместо typedef и перегрузить все необходимые операции, а также оператор приведения типа. В библиотеке Boost уже есть обертка для такой задачи — strong_typedef, что избавляет от необходимости писать её самим.

вторник, 23 ноября 2010 г.

Как так выходит, что разработчики, пока учатся в институте, на всех этапах участвуют в процессе обмена готовыми решениями — то есть, грубо говоря, качают из интернета курсовые, списывают на экзаменах и т.п.? А вот когда они же начинают писать программы, то каждый считает долгом написать свой велосипед, например, те же связанные списки, вместо того, чтобы поискать готовые решения, по крайней мере, в стандартной библиотеке или в Boost...

воскресенье, 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;