提升iterator_facade取消引用

时间:2011-09-24 22:05:44

标签: c++ templates boost iterator

我正在尝试使用boost迭代器外观来实现一个类的迭代器,该类存储data_t类型的元素的有序向量。目前我在解除引用方面遇到了麻烦。我只需要迭代器进行遍历和搜索,迭代器不需要改变Range对象的任何内部状态。

这是range.hpp:

#include <algorithm>
#include <vector>
#include <sstream>
#include <stdexcept>
#include <functional>

#include <boost/iterator/iterator_facade.hpp>

struct testRangeImpl{
    typedef unsigned int data_t;

    struct RangeOrdering : public std::binary_function< data_t const &, data_t const &, bool >{
        bool operator()(data_t const& a, data_t const& b){
            return a < b;
        }
    };
};


template<
    typename ImplT 
>
class SortedRange: public boost::iterator_facade< 
                    SortedRange< ImplT >,  //this type because of the CRTP
                    typename ImplT::data_t, //The type of the data
                    boost::bidirectional_traversal_tag //iterators can be incremented and decremented
                >{
    public:
        /*! this type */
        typedef SortedRange< ImplT > type;

        /*! The type of the implementation policy */
        typedef ImplT impl_t; 

        /*! The internal representation of an element */
        typedef typename impl_t::data_t data_t;

        /*! The internal representation of a range */
        typedef std::vector< data_t > range_t;

        /*! A member variabe to keep track of if the range has been sorted */
        bool m_sorted;

        /*! The actual range itself in its internal representation */
        range_t m_range;

        /*! The actual range itself in its internal representation */
        size_t m_range_size;

        /*! An exception indicating an invalid range */
        struct InvalidRangeException{};

        /*! Current element for iterator */
        size_t m_current_combo;

        enum class PositionClass {
            NOT_END,
            END,
            REND
        };

        explicit SortedRange( )
            : m_sorted(false), m_range(), m_range_size(0), m_current_combo(0) , m_posclass(PositionClass::END){
        }

        explicit SortedRange(std::vector < data_t > const& rg, size_t const& current_combo, PositionClass const& p )
            : m_sorted(false), m_range(rg), m_range_size(rg.size()), m_current_combo(current_combo) , m_posclass(p){
            if(rg.empty()){
                throw InvalidRangeException();
            }
            std::sort(m_range.begin(),m_range.end(),typename ImplT::RangeOrdering());
            m_sorted = true;
            //initialise();
        }

    protected:
        explicit SortedRange(std::vector < data_t > const& rg)
            : m_sorted(false), m_range(rg), m_range_size(rg.size()), m_current_combo(0) , m_posclass(PositionClass::NOT_END){
            if(rg.empty()){
                throw InvalidRangeException();
            }
            std::sort(m_range.begin(),m_range.end(),typename ImplT::RangeOrdering());
            m_sorted = true;
            //initialise();
        }   

        /*! Implementation policy object */
        impl_t m_impl;

        /*! construct a range with a specific internal state */
        explicit SortedRange(std::vector < data_t > const& rg, size_t const& current_combo)
            : m_sorted(false), m_range(rg), m_range_size(rg.size()), m_current_combo(current_combo) , m_posclass(PositionClass::NOT_END){
            if(rg.empty()){
                throw InvalidRangeException();
            }
            std::sort(m_range.begin(),m_range.end(),typename ImplT::RangeOrdering());
            m_sorted = true;
            //initialise();
        }
    public:

        size_t size(){
            m_range_size = m_range.size();
            return m_range_size;
        }

        /* Return first data */
        type begin() const {
            return type(m_range, 0);
        }

        type end() const {
            return type(m_range, m_current_combo, PositionClass::END);
        }

        type rend() const {
            return type(m_range, m_current_combo, PositionClass::REND);
        }

        /* Return last data */
        type rbegin() const {
            return type(m_range, m_range_size -1 );
        }

    private:
        friend class boost::iterator_core_access;

        /*! Position class */
        PositionClass m_posclass;

        /*! set up the initial state */
        void initialise() {
            std::sort(m_range.begin(),m_range.end());
            m_sorted == true;
        }

        /*! the first element */
        data_t first() const {
            return m_range[0];
        }

        /*! the last element */
        data_t last() const {
            return m_range[m_range_size - 1];
        }


        /*! return the current element */
        const data_t& dereference() const  {
            if(m_posclass == PositionClass::NOT_END) {
                return m_range[m_current_combo];
            }else {
                throw std::out_of_range("Attempt to dereference past the valid range");
            }
        }

        /*! get the next combination */
        void increment() {
            if(m_posclass != PositionClass::NOT_END)
                throw std::out_of_range("Cannot increment past the valid range");

            if(m_current_combo == m_range_size ) {
                //current combination is the last
                m_posclass = PositionClass::END;
            }
            m_current_combo++;
        }

        /*! get the previous combination */
        void decrement() {
            if(m_posclass != PositionClass::NOT_END)
                throw std::out_of_range("Cannot decrement past the valid range");

            if(m_current_combo == 0) {
                //current combination is the first
                m_posclass = PositionClass::REND;
            }
            m_current_combo--;  
        }

        /*! check for equality between two iterators. */
        bool equal(type const& other) const {
           if(m_posclass == PositionClass::NOT_END && 
           other.m_posclass == PositionClass::NOT_END) {

               return 
                   m_current_combo == other.m_current_combo &&
                   m_range == other.m_range;
           }
           else {
                return m_posclass == other.m_posclass && m_range == other.m_range;
           }
        }
};

struct Range : public SortedRange< testRangeImpl>{
    /*! An exception we throw if someone tries to construct an invalid range */
    struct InvalidRangeException : public SortedRange< testRangeImpl >::InvalidRangeException {};

    /*! Construct a range from a vector of unsigned ints */
    explicit Range(std::vector<unsigned int> const& r) : SortedRange<testRangeImpl>(r)
    {
        if(r.empty()){
            throw InvalidRangeException();
        }
    }
};

这是main.cpp:

#include <vector>
#include <iostream>
#include "range.hpp"
int main(void){
    std::vector<unsigned int> rg  = { 2 , 5 , 1 , 3 , 4 };
    Range test(rg);
    for(auto elem: test){
        std::cout << elem << " " ;
    }
    return 0;
}

编译会出现此错误:

/usr/include/boost/iterator/iterator_facade.hpp: In static member function ‘static typename Facade::reference boost::iterator_core_access::dereference(const Facade&) [with Facade = SortedRange<testRangeImpl>, typename Facade::reference = unsigned int&]’:
/usr/include/boost/iterator/iterator_facade.hpp:643:67:   instantiated from ‘boost::iterator_facade<I, V, TC, R, D>::reference boost::iterator_facade<I, V, TC, R, D>::operator*() const [with Derived = SortedRange<testRangeImpl>, Value = unsigned int, CategoryOrTraversal = boost::bidirectional_traversal_tag, Reference = unsigned int&, Difference = long int, boost::iterator_facade<I, V, TC, R, D>::reference = unsigned int&]’
main.cpp:9:17:   instantiated from here
/usr/include/boost/iterator/iterator_facade.hpp:517:32: error: invalid initialisation of reference of type ‘boost::iterator_facade<SortedRange<testRangeImpl>, unsigned int, boost::bidirectional_traversal_tag, unsigned int&, long int>::reference {aka unsigned int&}’ from expression of type ‘const data_t {aka const unsigned int}’

如何让它成为可用的迭代器类型?

1 个答案:

答案 0 :(得分:1)

您正在尝试对const值进行非const引用。出于某种原因,您已经确定dereference返回一个const引用,而不是遵循外观引用类型。修复它,它应该工作。