Как стать автором
Обновить

Итератор по кортежу (boost)

Время на прочтение 3 мин
Количество просмотров 1.2K
Итератор по кортежу И так, нам нам нужно огранизованно пройтись по всем членам кортежа. Мне это понадобилось для сохранения в xml — файл конструкций типа std::vector<boost::tuple<...>>. Кстати, пишу я это в Qt.

Ну да ладно, к делу.

Берём на вооружение библиотеку boost::fusion. В принципе итератор — указатель на первый элемент кортежа получить проще простого.

Вот наш кортеж к примеру.

typedef boost::tuple<int , char* , float> tup; // псведоним

tup my_tup(12, "two" , 3.4); // объявление и инициализация

boost::fusion::result_of::begin::type it(my_tup); // начальный итератор

std::cout << *it << '\n'; // 12



Инкременировать итератор сложнее, но тоже решаемо.

std::cout << *boost::fusion::next( it ) << '\n'; // "two"



На помощь была призвана шаблонная рекурсия.

Хотелось бы, что то типа:

template void work(R& item)
{
// тут обрабатываем член кортежа
std::cout << *item << '\n';
//
work( boost::fusion::next(item));
}




Но проблема была в остановке, как понять что нужно остановиться? В принципе когда итератор станет равным следующей конструкции, то нужно остановить всё это дело.

boost::fusion::result_of::end::type end; // конечный итератор



На помощь зовём boost::type_traits и boost::mpl::if_.

Надо бы сдеалть так, чтобы когда итератор поймёт, что дальше уже некуда, рекурсия оборвалась и пошла по другому пути. В качестве другого пути подсунем ей метод — пустышку, то есть, когда итератор дошёл до конца, он должен вызвать этот метод, вместо рабочего. Для этого засунем оба метода в структуры и поместим их там, как статические. Тогда вызовы этих методов будут похожими и отличаться только типом структур. А тип структуры нам нужно в последний момент подменить, для остановки рекурсии. Что бы поменять тип структуры используем boost::mpl::if_, в качестве условия которого засунем конструкцию boost::is_same из boost::type_traits. Это условие будет сверять каждый раз текущий итератор с конечным. Поехали:

struct do_work
{
template<typename T,typename R >
static void work(R& item ) // рабочий метод
{
#pragma message("******** process tuple **************") // для наглядности печтаем compile-time сообщения в отладку

// procees item
std::cout << *item << '\n';
//

typedef typename boost::fusion::result_of::end::type end; // тип конечного итератора
typedef typename boost::fusion::result_of::next::type next; // тип следующего итератора
typename next nex = boost::fusion::next( item ) ;
boost::mpl::if_<
boost::is_same<next , end>::type , // условие - провекрка
end_work , // конец рекурсии
do_work // следующий элемент
>::type::work( nex );
}

};

struct end_work // метод пустышка
{
template <typename T,typename R>
static void work(R& /*tip*/) // метод пустышка
{
#pragma message("******** end of tuple *************")
}
};

Теперь можно юзать , что мы тут нагородили.

int main()
{

typedef boost::tuple<int , char* , float> tup; // псевдоним
tup my_tup(12, "two" , 3.4); // объявление и инициализация

do_work::work( boost::fusion::begin(my_tup) ); // запуск

std::cin.ignore();
return 0;

}



При компиляции в окне отладки мы должны увидеть ,как компилятор три раза сработал рекурсивно, и на третьем разе споткнулся и съел метод пустышку.

******** process tuple **************
******** process tuple **************
******** process tuple **************
******** end of tuple *************



Всё.
ЗЫ Автор не претендует на оригинальность и професинальность, и грамотность кода и вообще не на что, просто если бы я такую статью прочитал три дня назад, сэкономил бы эти дни для моей жизни.
haccel.pp.ru
Теги:
Хабы:
-15
Комментарии 3
Комментарии Комментарии 3

Публикации

Истории

Ближайшие события

PG Bootcamp 2024
Дата 16 апреля
Время 09:30 – 21:00
Место
Минск Онлайн
EvaConf 2024
Дата 16 апреля
Время 11:00 – 16:00
Место
Москва Онлайн
Weekend Offer в AliExpress
Дата 20 – 21 апреля
Время 10:00 – 20:00
Место
Онлайн