1

Consider the following code:

#include <boost/iterator/iterator_facade.hpp>
#include <map>


    // Class implements an stl compliant iterator to access the "sections" stored within a configuration.
    template < typename _Iterator, typename _Reference >
        class Section
        : public boost::iterator_facade<
                     Section< _Iterator, _Reference >,
                     _Iterator,
                     boost::random_access_traversal_tag,
                     _Reference
                 >
        {
        private:
            // Define the type of the base class:
            typedef boost::iterator_facade<
                Section< _Iterator, _Reference >,
                _Iterator,
                boost::random_access_traversal_tag,
                _Reference
            > base_type;

        public:
            // The following type definitions are common public typedefs:
            typedef Section< _Iterator, _Reference >    this_type;
            typedef typename base_type::difference_type difference_type;
            typedef typename base_type::reference       reference;
            typedef _Iterator                           iterator_type;

        public:
            explicit Section( const iterator_type it )
            : m_it( it )
            { }

            // Copy constructor required to construct a const_iterator from an iterator:
            template < typename _U >
                Section( const Section< _U, _Reference > it )
                : m_it( it.m_it )
                { }

        private:
            // The following classes are friend of this class to ensure access onto the private member:
                                                                 friend class boost::iterator_core_access;
            template < typename _Iterator, typename _Reference > friend class Section;

            void increment( ){ ++m_it; }                                                          // Advance by one position.
            void decrement( ){ --m_it; }                                                          // Retreat by one position.
            void advance( const difference_type& n ){ m_it += n };                                // Advance by n positions.
            bool equal( const this_type& rhs ) const{ return m_it == rhs.m_it; }                  // Compare for equality with rhs.
            reference dereference( ) const { return m_it->second; }                               // Access the value referred to.
            difference_type distance_to( const this_type& rhs ) const{ return rhs.m_it - m_it; }  // Measure the distance to rhs.

        private:
            // Current "section" iterator:
            iterator_type m_it;
        };


struct Data
{
    void f( ) const
    { }
};

typedef std::map< int, Data > map_type;

typedef Section< const map_type::const_iterator, const Data& > iterator_type;

map_type g_map;

iterator_type begin( )
{
    return iterator_type( g_map.begin( ) );
}

void main( )
{
    iterator_type i = begin( );

    // i->f( ); // <---   error C2039: 'f' : is not a member of 'std::_Tree_const_iterator<_Mytree>'
    ( *i ).f( );
}

So the iterator facade shall return a reference to Data type. This works well when dereference operator is called but compile fails when operator->() is called. So I am a bit confused because operator->() tries to return a std::map::iterator. Any ideas ?

4

1 回答 1

1

迭代器在取消引用时返回一个迭代器。要获得f零件,您需要取消引用两次。

看起来很像您误解了iterator_facade. 第二个参数应该是任何迭代器类型(这是导致你所有麻烦的原因)。相反,您应该使用它来命名您的value_type

从您指定dereference操作 (and Ref) 并希望在 main ( i->f()) 中使用它的方式来看,您似乎只是想迭代地图的值。因此,我也会使用更具描述性的名称来重写整个内容,并且可以正常工作:

Live On Coliru

#include <boost/iterator/iterator_facade.hpp>
#include <map>

// Class implements an stl compliant iterator to access the "sections" stored within a configuration.
template <typename Map, typename Value = typename Map::mapped_type>
class MapValueIterator : public boost::iterator_facade<MapValueIterator<Map>, Value, boost::random_access_traversal_tag, Value const&> {
  private:
    // Define the type of the base class:
    typedef Value const& Ref;
    typedef boost::iterator_facade<MapValueIterator<Map>, Value, boost::random_access_traversal_tag, Ref> base_type;

  public:
    // The following type definitions are common public typedefs:
    typedef MapValueIterator<Map> this_type;
    typedef typename base_type::difference_type difference_type;
    typedef typename base_type::reference reference;
    typedef typename Map::const_iterator iterator_type;

  public:
    explicit MapValueIterator(const iterator_type it) : m_it(it) {}

    // Copy constructor required to construct a const_iterator from an iterator:
    template <typename U, typename V> MapValueIterator(const MapValueIterator<U,V> it) : m_it(it.m_it) {}

  private:
    // The following classes are friend of this class to ensure access onto the private member:
    friend class boost::iterator_core_access;
    template <typename U, typename V> friend class MapValueIterator;

    void increment()                                        { std::advance(m_it);      } // Advance by one position.
    void decrement()                                        { std::advance(m_it, -1);  } // Retreat by one position.
    void advance(const difference_type &n)                  { std::advance(m_it, n);   } // Advance by n positions.
    bool equal(const this_type &rhs) const                  { return m_it == rhs.m_it; } // Compare for equality with rhs.
    reference dereference() const                           { return m_it->second;     } // Access the value referred to.
    difference_type distance_to(const this_type &rhs) const { return rhs.m_it - m_it;  } // Measure the distance to rhs.

  private:
    // Current iterator:
    iterator_type m_it;
};

#include <iostream>

struct Data {
    void f() const {
        std::cout << __PRETTY_FUNCTION__ << "\n";
    }
};

typedef std::map<int, Data> map_type;

template <typename Map>
MapValueIterator<Map> map_value_iterator(Map const& m) {
    return MapValueIterator<Map>(m.begin());
}


int main() {
    map_type g_map;
    auto i = map_value_iterator(g_map);

    i->f();
}

打印输出

void Data::f() const

如您所料。

请注意,有很多地方我使用标准库设施实现了成员函数。还要注意,迭代器“模仿”随机访问,但它不会具有预期的性能特征(增量为 O(n))。

最后说明:我建议不要使用隐式转换构造函数。我认为你可以没有它。


¹ 引用类型通常应该是相同的(但经过引用限定),除非在极少数情况下您实际上“代理”了这些值。这是一个高级主题,很少应该使用。

于 2015-09-27T20:45:00.573 回答