2010-06-08 4 views
4

Hy there,Итератор для boost :: variant

Я пытаюсь адаптировать существующий код для boost :: variant. Идея заключается в использовании boost :: variant для гетерогенного вектора. Проблема в том, что остальная часть кода использует итераторы для доступа к элементам вектора. Есть ли способ использовать boost :: variant с итераторами?

Я попытался

typedef boost::variant<Foo, Bar> Variant; 
std::vector<Variant> bag; 
std::vector<Variant>::iterator it; 
for(it= bag.begin(); it != bag.end(); ++it){ 

cout<<(*it)<<endl; 
} 

Но это не сработало.

EDIT: Благодарим за помощь! Но в моем дизайне мне нужно получить один элемент из списка и передать его другим частям кода (и это может быть неприятно, поскольку я использую GSL). Идея использования итератора заключается в том, что я могу передать итератор функции, и функция будет работать с данными возврата из этого конкретного элемента. Я не вижу, как это сделать, используя for_each. Мне нужно сделать что-то подобное:

for(it=list.begin(); it!=list.end();++it) { 
    for(it_2=list.begin(); it_2!=list.end();++it_2) { 

    if(it->property() != it_2->property()) { 

     result = operate(it,it_2); 

     } 
    } 

} 

Спасибо!

ответ

8

Ну, конечно, есть. Выделение итераторов, естественно, даст ссылку boost::variant<...> или константу-ссылку.

Однако это означает, что остальная часть кода должна быть осведомлена о вариантах. И особенно используйте команду boost::static_visitor для выполнения операций над вариантами.

EDIT:

Легко!

struct Printer: boost::static_visitor<> 
{ 
    template <class T> 
    void operator()(T const& t) const { std::cout << t << std::endl; } 
}; 

std::for_each(bag.begin(), bag.end(), boost::apply_visitor(Printer()); 

Обратите внимание, что при написании посетителя автоматически выдается предикат для алгоритмов STL, miam!

Теперь для выдачи возвращаемого значения:

class WithReturn: boost::static_visitor<> 
{ 
public: 
    WithReturn(int& result): mResult(result) {} 

    void operator()(Foo const& f) const { mResult += f.suprise(); } 
    void operator()(Bar const& b) const { mResult += b.another(); } 

private: 
    int& mResult; 
}; 


int result; 
std::for_each(bag.begin(), bag.end(), boost::apply_visitor(WithReturn(result))); 

EDIT 2:

Это легко, но на самом деле нужно немного коучинга :)

Во-первых, отметим, существует 2 различных операции: != и operate

struct PropertyCompare: boost::static_visitor<bool> 
{ 
    template <class T, class U> 
    bool operator()(T const& lhs, U const& rhs) 
    { 
    return lhs.property() == rhs.property(); 
    } 
}; 

struct Operate: boost::static_visitor<result_type> 
{ 
    result_type operator()(Foo const& lhs, Foo const& rhs); 
    result_type operator()(Foo const& lhs, Bar const& rhs); 
    result_type operator()(Bar const& lhs, Bar const& rhs); 
    result_type operator()(Bar const& lhs, Foo const& rhs); 
}; 

for(it=list.begin(); it!=list.end();++it) { 
    for(it_2=list.begin(); it_2!=list.end();++it_2) { 

    if(!boost::apply_visitor(PropertyCompare(), *it, *it_2)) { 

     result = boost::apply_visitor(Operate(), *it, *it_2)); 

    } 

    } 
} 

Для каждого здесь не так хорошо, из-за этого if. Это сработало бы, если бы можно было каким-то образом определить if в operate.

Также обратите внимание, что я пропускаю не итераторы, а ссылки.

+0

Усиление :: static_visitor полезно работать с элементами, но не работает, когда класс должен возвращать некоторые данные. Я пробовал использовать итераторы для boost :: ptr_vector >, но что-то вроде этого не получилось: typedef boost :: variant Variant; std :: vector bag; std :: vector :: iterator it; для (это = bag.begin(); это! = Сумка.конец(); ++ it) { cout << (* it) << endl; } – Ivan

+0

Отредактирована запись, чтобы проиллюстрировать ее использование. –

+0

Большое спасибо. Все еще пытаюсь приспособить концепцию к моему существующему коду при слишком большом изменении. Новое редактирование выше. – Ivan

Смежные вопросы