为迭代器调用 const 而不是非常量访问运算符
Calls const instead of non-const access operator for 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);}
据我所知,它指的是访问运算符的非常量版本,但是为什么,如果我在这里明确使用常量迭代器呢?
当您在 for 循环中使用 const_iterator it
时,it
属于 const_iterator
类型,但它本身是非常量。
因此使用其成员函数将使用非常量成员,这在 my_iterator
存储真正的 list::const_iterator
时不起作用。在表达式 &(*m_it)
中,*m_it
引用的元素是 const,因此您无法获取该对象的非常量地址:
error: invalid conversion from ‘const Data*’
经过一番调查,我终于找到了问题所在,所以我发布了上述代码的正确、可编译版本。以下是要点:
-- 主要问题是我为基础 std::iterator class 定义的模板参数不足。它需要 5 个参数,但我只定义了前 2 个,其余的依赖于默认类型分配。这是一个错误。例如,默认情况下 pointer
被定义为 value_type*
,但我需要的实际上是常量迭代器 const value_type*
。因此,我定义了所有 5 个模板参数。
-- 不需要 operator*()
和 operator->()
.
这两个版本
-- 我还添加了另一个模板构造函数,以允许将非常量迭代器分配给常量迭代器。
下面是我努力的结果。
#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;
}
}
我想在一个 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);}
据我所知,它指的是访问运算符的非常量版本,但是为什么,如果我在这里明确使用常量迭代器呢?
当您在 for 循环中使用 const_iterator it
时,it
属于 const_iterator
类型,但它本身是非常量。
因此使用其成员函数将使用非常量成员,这在 my_iterator
存储真正的 list::const_iterator
时不起作用。在表达式 &(*m_it)
中,*m_it
引用的元素是 const,因此您无法获取该对象的非常量地址:
error: invalid conversion from ‘const Data*’
经过一番调查,我终于找到了问题所在,所以我发布了上述代码的正确、可编译版本。以下是要点:
-- 主要问题是我为基础 std::iterator class 定义的模板参数不足。它需要 5 个参数,但我只定义了前 2 个,其余的依赖于默认类型分配。这是一个错误。例如,默认情况下 pointer
被定义为 value_type*
,但我需要的实际上是常量迭代器 const value_type*
。因此,我定义了所有 5 个模板参数。
-- 不需要 operator*()
和 operator->()
.
-- 我还添加了另一个模板构造函数,以允许将非常量迭代器分配给常量迭代器。
下面是我努力的结果。
#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;
}
}