为迭代器调用const而不是非const访问运算符

时间:2016-02-10 14:49:14

标签: c++ iterator const-iterator

我想在一个STL迭代器之上构建一个自定义迭代器。这是代码的精简版本,我希望可以编译:

#include <cstddef>
#include <iterator>
#include <list>

class Data
{
public:
  double x;
};

typedef std::list<Data> list_of_data;

template <class IteratorType>
class my_iterator :
     public std::iterator<std::bidirectional_iterator_tag,
                          typename IteratorType::value_type >
{
public:
  //type of itself
  typedef my_iterator self;
  //type of underlying iterator
  typedef IteratorType list_iterator_type;

  my_iterator(list_iterator_type it) :
    m_it(it)
  {}//constructor.

  my_iterator(const self& source) :
    m_it(source.m_it)
  {}

  self& operator=(const self& source)
  {
    m_it = source.m_it;
    return *this;
  }//operator=

  bool operator==(self other)
  {
    return m_it == other.m_it;
  }

  bool operator!=(self other)
  {
    return m_it != other.m_it;
  }

  inline typename self::reference operator*()
  { return (*m_it);}

  inline const typename self::reference operator*() const
    { return (*m_it); }

  inline typename self::pointer operator->()
    { return &(*m_it); }

  inline const typename self::pointer operator->() const
    { return &(*m_it); }

  inline self& operator++()
  {
    ++m_it;
  }//operator++

  inline self operator++(int)
  {
    self tmp(*this);
    ++(*this);
    return tmp;
  }//operator++(int)

private:

  list_iterator_type m_it;
};

///non constant iterator over cells.
typedef my_iterator<list_of_data::iterator> iterator;
///constant iterator over cells.
typedef my_iterator<list_of_data::const_iterator> const_iterator;

int main()
{
  list_of_data test_list;
  Data a;
  test_list.push_back(a);
  test_list.push_back(a);
  test_list.push_back(a);
  for(const_iterator it  = const_iterator(test_list.begin()); 
                     it != const_iterator(test_list.end()); ++it)
  {
    double x = it->x;
    double y = (*it).x;
  }
}

但是它显示以下错误消息:

test_list.cpp: In instantiation of ‘typename my_iterator<IteratorType>::self::pointer my_iterator<IteratorType>::operator->() [with IteratorType = std::_List_const_iterator<Data>; typename my_iterator<IteratorType>::self::pointer = Data*]’:
test_list.cpp:92:18:   required from here
test_list.cpp:55:21: error: invalid conversion from ‘const Data*’ to ‘std::iterator<std::bidirectional_iterator_tag, Data, long int, Data*, Data&>::pointer {aka Data*}’ [-fpermissive]
     { return &(*m_it); }
                     ^
test_list.cpp: In instantiation of ‘typename my_iterator<IteratorType>::self::reference my_iterator<IteratorType>::operator*() [with IteratorType = std::_List_const_iterator<Data>; typename my_iterator<IteratorType>::self::reference = Data&]’:
test_list.cpp:93:18:   required from here
test_list.cpp:49:18: error: invalid initialization of reference of type ‘std::iterator<std::bidirectional_iterator_tag, Data, long int, Data*, Data&>::reference {aka Data&}’ from expression of type ‘const Data’
   { return (*m_it);}

据我所知,它指的是访问运算符的非const版本,但是为什么,如果我在这里显式使用常量迭代器呢?

2 个答案:

答案 0 :(得分:0)

在for循环中使用const_iterator it时,it的类型为const_iterator,但它本身是非常量的。

因此,使用其成员函数将使用非const成员,当my_iterator存储真实list::const_iterator时,该成员不起作用。在表达式&(*m_it)中,*m_it引用的元素是const,因此您无法获得该对象的非const地址:

  

错误:来自'const Data *'的无效转换

答案 1 :(得分:0)

经过一番调查后我终于发现了问题,所以我发布了上述代码的正确,可编译的版本。以下是重点:

- 主要问题是我为base std :: iterator类定义了模板参数。它需要5个参数,但我只定义了前2个,依赖于其余的默认类型赋值。这是一个错误。例如,默认情况下pointer被定义为value_type*,但我需要的是常量迭代器实际上const value_type*。因此,我定义了所有5个模板参数。

- 无需拥有operator*()operator->()的两个版本。

- 我还添加了另一个模板化构造函数,允许将非const迭代器赋值给const。

以下是我努力的结果。

#include <cstddef>
#include <iostream>
#include <iterator>
#include <list>

class Data
{
public:
  double x;
};

typedef std::list<Data> list_of_data;

template <class IteratorType>
class my_iterator :
     public std::iterator<std::bidirectional_iterator_tag,
                          typename IteratorType::value_type,
                          typename IteratorType::difference_type,
                          typename IteratorType::pointer,
                          typename IteratorType::reference>
{
public:
  //type of itself
  typedef my_iterator self;
  //type of iterator over cells
  typedef IteratorType list_iterator_type;

  my_iterator(list_iterator_type it) :
    m_it(it)
  {}//constructor.

  my_iterator(const self& source) :
    m_it(source.m_it)
  {}

  template<class another_iterator>
  my_iterator(const my_iterator<another_iterator>& source) :
    m_it(source.m_it)
  {}

  self& operator=(const self& source)
  {
    m_it = source.m_it;
    return *this;
  }//operator=

  bool operator==(self other) const
  {
    return m_it == other.m_it;
  }

  bool operator!=(self other) const
  {
    return m_it != other.m_it;
  }

  inline typename self::reference operator*() const
  { return (*m_it);}

  inline typename self::pointer operator->() const
    { return &(*m_it); }

  inline self& operator++()
  {
    ++m_it;
    return (*this);
  }//operator++

  inline self operator++(int)
  {
    self tmp(*this);
    ++(*this);
    return tmp;
  }//operator++(int)

private:

  list_iterator_type m_it;
};

///non constant iterator over cells.
typedef my_iterator<list_of_data::iterator> iterator;
///constant iterator over cells.
typedef my_iterator<list_of_data::const_iterator> const_iterator;

int main()
{
  list_of_data test_list;
  Data a;
  test_list.push_back(a);
  test_list.push_back(a);
  test_list.push_back(a);
  for(iterator it  = iterator(test_list.begin()); 
                     it != iterator(test_list.end()); ++it)
  {
    it->x = 2;
  }
  for(const_iterator it  = const_iterator(test_list.begin()); 
                     it != const_iterator(test_list.end()); ++it)
  {
    std::cout << "  it->x =" << it->x << std::endl;
    std::cout << "(*it).x =" << (*it).x << std::endl;
  }
}