2014-12-21 2 views
1

Я реализовал тривиальный класс MyClass, у которого есть массив, выделенный в нем new (я знаю, что могу использовать контейнер STL, но я пытаюсь понять, как они работают). Я также создал итератор подкласс, способный итерацию по всем элементам MyClass объекта:Невозможно получить BOOST_FOREACH для работы с моим пользовательским классом

class MyIterator : public iterator<forward_iterator_tag,int> 
{ 
private: 
    int* data= nullptr; 
    int length; 
    int pointer=0; 
    int nullvalue=0; 
public: 
    MyIterator(int* data, int length, bool end= false) 
    { 
     this->data= data; 
     this->length= length; 
     if(end) 
      pointer=-1; 
    } 
    ~MyIterator() 
    { 
     delete[] data; 
    } 
    MyIterator& operator++() 
    { 
     if(pointer!= length-1) 
     { 
      pointer++; 
     } 
     else 
     { 
      pointer= -1; 
     } 
     return *this; 
    } 
    bool operator==(const MyIterator& other) 
    { 
     return pointer==other.pointer; 
    } 
    bool operator!=(const MyIterator& other) 
    { 
     return pointer!= other.pointer; 
    } 
    int& operator*() 
    { 
     if(pointer==-1) 
      return nullvalue; 
     else 
      return data[pointer]; 
    } 
}; 

class MyClass 
{ 
private: 
    int* data= nullptr; 
    int length= 100; 
public: 
    MyClass() 
    { 
     data= new int[length]; 
     for(int i=0; i<length;i++) 
      data[i]=i+1; 
    } 
    iterator<forward_iterator_tag,int> begin() 
    { 
     return MyIterator(data,length); 
    } 
    iterator<forward_iterator_tag,int> end() 
    { 
     return MyIterator(data,length,true); 
    } 
}; 

Хотя итератор работает, если я использую это так:

for(MyIterator i= MyClass_instance.begin(); i!=MyClass_instance.end();i++) {...} 

Это не работает, если Я стараюсь использовать его с BOOST_FOREACH:

BOOST_FOREACH(int i, MyClass_instance) {...} 

Эти ошибки, которые я получаю:

enter image description here

ответ

3
  • Вы нарезка свой итератор, возвращая их как std::iterator<>значением. Вы не можете сделать это.

    Возвращаясь по ссылке, вы избежите проблемы с нарезкой , но вводит худшую проблему: она возвращает ссылку на временную¹.

    Следовательно, исправьте его, вернув свой действительный номер итератора.

  • В вашем типе отсутствовал константный итератор.

  • Все члены итератора не были const-correct.

  • Кроме того, согласно странице Extensibility это выглядит, как вам нужно добавить

    namespace boost { 
        template<> struct range_mutable_iterator<MyClass> { 
         typedef MyClass::MyIterator type; 
        }; 
    
        template<> struct range_const_iterator<MyClass> { 
         typedef MyClass::MyConstIterator type; 
        }; 
    } 
    
  • Существует серьезной проблемы с реализацией Rule-Of-Three для вашего типа итератора (What is The Rule of Three?) ,

    Вы удаляете данные контейнера каждый раз, когда итератор исчезает. И MyClass сама не освобождает данные ...

Закрепление большинство из выше (?):

Live On Coliru

#include <iterator> 
#include <boost/foreach.hpp> 

class MyClass 
{ 
private: 
    int* data = nullptr; 
    int length = 100; 

public: 
    class MyIterator : public std::iterator<std::forward_iterator_tag, int> 
    { 
     public: 
      MyIterator(int* data, int length, bool end = false) 
      { 
       this->data= data; 
       this->length= length; 
       if(end) 
        pointer=-1; 
      } 
      MyIterator& operator++() 
      { 
       if(pointer!= length-1) { 
        pointer++; 
       } 
       else { 
        pointer= -1; 
       } 
       return *this; 
      } 

      bool operator==(const MyIterator& other) const { return pointer==other.pointer; } 
      bool operator!=(const MyIterator& other) const { return pointer!= other.pointer; } 
      int& operator*() const 
      { 
       if(pointer==-1) 
        return nullvalue; 
       else 
        return data[pointer]; 
      } 
     private: 
      value_type* data  = nullptr; 
      int length; 
      int pointer   = 0; 
      mutable value_type nullvalue = 0; 
    }; 

    class MyConstIterator : public std::iterator<std::forward_iterator_tag, const int> 
    { 
     public: 
      MyConstIterator(int const* data, int length, bool end = false) 
      { 
       this->data= data; 
       this->length= length; 
       if(end) 
        pointer=-1; 
      } 
      MyConstIterator& operator++() 
      { 
       if(pointer!= length-1) { 
        pointer++; 
       } 
       else { 
        pointer= -1; 
       } 
       return *this; 
      } 

      bool operator==(const MyConstIterator& other) const { return pointer==other.pointer; } 
      bool operator!=(const MyConstIterator& other) const { return pointer!= other.pointer; } 
      int const& operator*() const 
      { 
       if(pointer==-1) 
        return nullvalue; 
       else 
        return data[pointer]; 
      } 
     private: 
      value_type* data  = nullptr; 
      int length; 
      int pointer   = 0; 
      value_type nullvalue = 0; 
    }; 

public: 
    typedef MyIterator iterator_type; 
    typedef MyConstIterator const_iterator_type; 

    MyClass() 
    { 
     data= new int[length]; 
     for(int i=0; i<length;i++) 
      data[i]=i+1; 
    } 
    ~MyClass() { 
     delete[] data; 
    } 
    iterator_type begin()    { return MyIterator(data,length);  } 
    iterator_type end()    { return MyIterator(data,length,true); } 
    const_iterator_type begin() const { return MyConstIterator(data,length);  } 
    const_iterator_type end() const { return MyConstIterator(data,length,true); } 
}; 

namespace boost { 
    template<> struct range_mutable_iterator<MyClass> { 
     typedef MyClass::MyIterator type; 
    }; 

    template<> struct range_const_iterator<MyClass> { 
     typedef MyClass::MyConstIterator type; 
    }; 
} 

#include <iostream> 

int main() 
{ 
    MyClass c; 
    BOOST_FOREACH(int i, c) { 
     std::cout << i << "\n"; 
    } 
} 

¹ (если вы не хранить итераторы где-то в другом месте, но это было бы огромным анти-шаблоном по многим причинам)

+0

рабочий образец ** [Live On Coliru] (http: //coliru.stacked-crooked.com/a/5aded9c74b968671) ** – sehe

+0

Я получаю непонятную синтаксическую ошибку: «Нет соответствующей функции для вызова« deref »», в той же строке, где вы вызываете BOOST_FOREACH. Проблема заключается в структуре с именем struct __iterator_traits_impl <_Iter, true>, внутри заголовка итератора STL. –

+0

@RamyAlZuhouri интересно. Вы заметили живой концерт? У меня возникнет соблазн предположить, что вы делаете что-то другое. Я не могу действительно рассуждать о коде, который вы не показываете. – sehe