问题描述
template <class T,class Link>
class single_iterator
{
public:
using iterator_category = std::forward_iterator_tag;
//A value is not T but T*,because the list is a contaner of elements of type T *.
using value_type = T *;
//required by std::iterator_traits in GCC.
using difference_type = std::ptrdiff_t;
using pointer = value_type *;
using reference = value_type &;
single_iterator(Link *p) : pCur(p) {}
T * operator-> () const { return cur(); }
T * operator* () const { return cur(); }
single_iterator & operator++ ()
{
this->MoveNext();
return *this;
}
single_iterator operator++ (int)
{
single_iterator tmp = *this;
this->MoveNext();
return tmp;
}
bool operator == (const single_iterator & r) const
{
return this->link() == r.link();
}
bool operator != (const single_iterator & r) const
{
return !(*this == r);
}
private:
//! Results in undefined behavior if the iterator is end().
T * cur() const { return static_cast<T *>(pCur); }
void MoveNext() { pCur = pCur->next(); }
Link * link() const { return pCur; }
Link * pCur;
};
然后我在容器中声明iterator
和const_iterator
并实现begin()
和end()
:
template <class T,class Link,class Derived>
class container
{
public:
using value_type = T *;
using iterator = single_iterator<T,Link>;
using const_iterator = single_iterator<const T,const Link>;
iterator begin() { return first(); }
const_iterator begin() const { return first(); }
};
当我使用这样的迭代器时,它不会编译:
#include <iostream>
#include <vector>
struct A
{
void func()
{
container<A>::const_iterator i = m_v.begin();
}
container<A> m_v;
};
int main()
{
A a;
a.func();
return 0;
}
因为不能从const_interator
构造iterator
。
通过最少的代码重复并为const_iterator
和iterator
定义单独的类来实现此转换的正确方法是什么?
请参见the same code with std::vector。
EDIT1 :类似这样的代码:
struct A
{
operator A() { return *this;}
};
int main()
{
A a;
return 0;
}
因此可以通过添加const
来定义类型转换运算符,并且const_iterator
将转换为自身。但是看起来有点奇怪...
解决方法
您只需提供一个隐式转换运算符,即可将迭代器的非const版本转换为const版本。一个简短的例子:
template<class T>
class my_iter
{
public:
// Non-const iterator can be implicitly converted to const
operator my_iter<const T>() const {
// Replace this with however your iterator is constructed
return {};
}
};
编辑:
该解决方案不允许典型的比较运算符在const
和非const
迭代器之间进行互操作,这是一个问题。解决方法是强制比较运算符仅接受const
迭代器作为参数。传递非const
迭代器时,它将隐式使用转换运算符。例子:
bool operator==(const my_iter<std::add_const_t<T>> & p_other) const
{
// Compare...
}
这还有一个缺点,即无法访问参数的private
。一种解决方法是将iterator<const T>
设为friend class
的{{1}}:
iterator<T>
另一种方法是将#include <type_traits>
template<class T>
class my_iter
{
public:
// Non-const iterator can be implicitly converted to const
operator my_iter<const T>() const {
// Replace this with however your iterator is constructed
return {};
}
bool operator==(const my_iter<std::add_const_t<T>> & p_other) const
{
return state == p_other.state; // Works even if `state` is `private`
}
private:
// Some iterator implementation detail
T * state = nullptr;
// `iter<T>` and `iter<const T>` are friends of each other
friend class my_iter<std::remove_const_t<T>>;
friend class my_iter<std::add_const_t<T>>;
};
显式转换为*this
,并仅使用iterator<const T>&
来为operator==
实现iterator<T>
,这两个对象的私有成员都可以访问。
iterator<T>
使用任何一种解决方案,都可以对bool operator==(const my_iter<std::add_const_t<T>> & p_other) const
{
if constexpr (std::is_same_v<std::decay_t<decltype(p_other)>,my_iter<T>>) {
// `*this` and `p_other` are both `const T` iterators
// You may access the private members of both objects here
return state == p_other.state; // Works even if `state` is `private`
}
else {
// The `p_other` is not the same type as `*this`
return static_cast<const my_iter<const T> &>(*this) == p_other;
}
}
进行重复。您可以从operator<
构建为其他比较运算符。例如,operator<
可以实现为operator>(a,b)
,而return b < a;
可以实现为operator==(a,b)