Итератор для Boost :: Вариант - PullRequest
4 голосов
/ 09 июня 2010

Hy там,

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

Я пробовал

 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;
 }

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

РЕДАКТИРОВАТЬ: Спасибо за вашу помощь! Но в моем проекте мне нужно получить один элемент из списка и передать его другим частям кода (и это может быть неприятно, поскольку я использую 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);

       }
    }

}

Спасибо!

1 Ответ

8 голосов
/ 09 июня 2010

Ну, конечно, есть. Разыменование итераторов, естественно, приведет к 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, миам!

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

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)));

РЕДАКТИРОВАТЬ 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.

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

...