[英]Custom container list: problem with compiling from iterator to const_iterator
I am trying to recreate some of the C++ containers for a school project and for that I had to also implement iterators.我正在尝试为学校项目重新创建一些 C++ 容器,为此我还必须实现迭代器。 I am currently working on the List container and I am facing a conversion problem.
我目前正在处理 List 容器,并且遇到了转换问题。 Here are the parts of the code that are involved:
以下是涉及的代码部分:
template <class T> struct Elem { Elem *prev; T data; Elem *next; };
template <class T> class BidirectionalIterator { public: typedef BidirectionalIterator iterator; typedef T value_type; typedef size_t size_type; BidirectionalIterator() { _ptr = nullptr; }; BidirectionalIterator(Elem<value_type> *ptr) { *this->_ptr = ptr; }; BidirectionalIterator(const iterator &x) { *this->_ptr = x._ptr; }; ~BidirectionalIterator() {}; iterator &operator=(const iterator &x) { *this->_ptr = x._ptr; return (*this); }; [...] };
template <class T, class Alloc = std::allocator<T>> class list { public: typedef T value_type; typedef BidirectionalIterator<T> iterator; typedef BidirectionalIterator<const T> const_iterator; typedef size_t size_type; /* CONSTRUCTORS */ [...] list(const list &x) { _init_list(); assign(x.begin(), x.end()); }; /* ITERATORS */ iterator begin() { return (iterator(_start)); }; const_iterator begin() const { return (const_iterator(_start)); }; iterator end() { return (iterator(_tail)); }; const_iterator end() const { return (const_iterator(_tail)); }; /* ASSIGN */ void assign(iterator first, iterator last); void assign(const_iterator first, const_iterator last); [...] private: Elem<value_type> *_head; Elem<value_type> *_start; Elem<value_type> *_end; Elem<value_type> *_tail; [...] };
In my main program I' m just calling a function (T being an int) that implicitely calls the copy constructor:在我的主程序中,我只是调用一个隐式调用复制构造函数的 function(T 是一个 int):
void print_content(ft::list<T> lst);
But when I compile i get this:但是当我编译时,我得到了这个:
./List.hpp:71:12: error: no matching conversion for functional-style cast from 'Elem<ft::list<int, std::allocator<int>
>::value_type> *const' (aka 'Elem<int> *const') to 'ft::list<int, std::allocator<int> >::const_iterator' (aka
'BidirectionalIterator<const int>')
return (const_iterator(_start));
^~~~~~~~~~~~~~~~~~~~~
./List.hpp:53:13: note: in instantiation of member function 'ft::list<int, std::allocator<int> >::begin' requested
here
assign(x.begin(), x.end());
./../Iterator/BidirectionalIterator.hpp:45:3: note: candidate constructor not viable: no known conversion from
'Elem<ft::list<int, std::allocator<int> >::value_type> *const' (aka 'Elem<int> *const') to
'Elem<ft::BidirectionalIterator<const int>::value_type> *' (aka 'Elem<const int> *') for 1st argument
BidirectionalIterator(Elem<value_type> *ptr) {
I don't know how to fix that problem.我不知道如何解决这个问题。 I already tried to delete the const attribute from my copy constructor and it works, but it needs to be const (for the rest of my project cause I'm implementing the relational operators that call a const list, and also to respect the original container constructor).
我已经尝试从我的复制构造函数中删除 const 属性并且它可以工作,但它需要是 const (对于我项目的 rest,因为我正在实现调用 const 列表的关系运算符,并且还要尊重原始容器构造函数)。
Does anyone have an idea?有人有想法吗?
You try to create an Elem<const int>*
from an Elem<int> *const
.您尝试从
Elem<int> *const
创建Elem<const int>*
。
I suggest making the iterator's pointer Elem<std::remove_const_t<T>>*
(even for a const_iterator
) but let dereferencing a const_iterator
return a T const&
or T const *
.我建议制作迭代器的指针
Elem<std::remove_const_t<T>>*
(即使对于const_iterator
)但让取消引用const_iterator
返回T const&
或T const *
。
Example:例子:
template <class T>
class BidirectionalIterator {
public:
using value_type = T;
using reference = value_type&;
using pointer = value_type*;
using size_type = std::size_t;
BidirectionalIterator() : _ptr(nullptr) {};
BidirectionalIterator(Elem<std::remove_const_t<value_type>>* ptr) : _ptr(ptr) {};
BidirectionalIterator(const BidirectionalIterator& x) {
_ptr = x._ptr;
};
BidirectionalIterator& operator=(const BidirectionalIterator& x) {
_ptr = x._ptr;
return *this;
};
reference operator*() const { return _ptr->data; }
pointer operator->() const { return &_ptr->data; }
Elem<std::remove_const_t<value_type>>* _ptr;
};
A slightly better version to let you create list
s of const T
s and to also let you convert iterator
s to const_iterator
s (but not the other way around) to be able to compare iterators could look like this:一个稍微好一点的版本可以让您创建
const T
的list
并且还可以让您将iterator
转换为const_iterator
(但不能反过来)以便能够比较迭代器,如下所示:
#include <memory>
#include <type_traits>
template <class T, class ElemType> // const or non-const T and the type used in Elem
class BidirectionalIterator {
public:
using value_type = T;
using reference = value_type&;
using pointer = value_type*;
using size_type = std::size_t;
BidirectionalIterator() : _ptr(nullptr) {};
BidirectionalIterator(Elem<ElemType>* ptr) : _ptr(ptr) {};
// let a conversion constructor of the const_iterator read _ptr
friend class BidirectionalIterator<const ElemType, ElemType>;
// enable a const_iterator to be created from a non-const iterator via
// a conversion constructor
template<typename U = T, typename V = ElemType,
std::enable_if_t<std::is_const_v<U>&&!std::is_const_v<V>, int> = 0
>
BidirectionalIterator(const BidirectionalIterator<ElemType, ElemType>& x) :
_ptr(x._ptr) {}
// normal copy ctor
BidirectionalIterator(const BidirectionalIterator& x) : _ptr(x._ptr) {}
BidirectionalIterator& operator=(const BidirectionalIterator& x) {
_ptr = x._ptr;
return *this;
};
// the conversion constructor lets you compare a const_iterator and an iterator
bool operator==(const BidirectionalIterator& rhs) const {
return _ptr == rhs._ptr;
}
bool operator!=(const BidirectionalIterator& rhs) const {
return !(_ptr == rhs._ptr);
}
reference operator*() const { return _ptr->data; }
pointer operator->() const { return &_ptr->data; }
private:
Elem<ElemType>* _ptr;
};
// iterator == const_iterator, swap order to use member operator==
template<typename T>
bool operator==(const BidirectionalIterator<T, T>& a,
const BidirectionalIterator<const T, T>& b) {
return b == a;
}
// iterator != const_iterator, swap order to use member operator!=
template<typename T>
bool operator!=(const BidirectionalIterator<T, T>& a,
const BidirectionalIterator<const T, T>& b) {
return b != a;
}
With this iterator definition, you'd need to define your iterator
and const_iterator
slightly different.使用此迭代器定义,您需要定义
iterator
和const_iterator
略有不同。
template <class T, class Alloc = std::allocator<T>>
class list {
public:
using value_type = T;
using iterator = BidirectionalIterator<T, T>;
using const_iterator = BidirectionalIterator<const T, T>;
//...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.