boost :: iterator_facade operator->()无法编译

时间:2015-09-26 14:06:43

标签: boost iterator-facade

请考虑以下代码:

#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( );
}

因此迭代器外观应返回对数据类型的引用。这在调用dereference运算符时很有效,但在调用operator-&gt;()时编译失败。所以我有点困惑因为operator-&gt;()试图返回一个std :: map :: iterator。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

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

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

从您指定dereference操作(和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))。

最后注意:我建议不要使用隐式转换构造函数。我想你可以不用它。

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