I have implemented a doubly-linked list, and created an iterator which extends std::iterator. I'm now trying to create a const version.
I tried:
typename typedef list_iterator<T_> iterator;
typename typedef list_iterator<T_> const const_iterator;
If I do this though, I get this error:
error C2678: binary '--' : no operator found which takes a left-hand operand of type 'const list_iterator<T_>' (or there is no acceptable conversion)
Here is my operator--:
list_iterator& operator -- ()
{
_current = _current->_previous;
return *this;
}
list_iterator operator--(int) // postfix
{
list_iterator hold = *this;
--*this;
return list_iterator( hold );
}
If I put
list_iterator operator--() const
... I'm not able to modify the value of _current
How do I make my iterator now work like a const_iterator so that from my linked list I can call get the const version of begin() and end(), as well as cbegin() and cend()?
Right. The problem is your declaration of your const_iterator typedef. (See How to correctly implement custom iterators and const_iterators? )
Instead of
typename typedef list_iterator<T_> const const_iterator;
you want
typename typedef list_iterator<const T_> const_iterator;
Related
I am trying to make my own mini-vector class and I am attempting to replicate some of the functions, but I can not get them to behave the same way when passing calls such as begin() and end() as parameters - the compiler doesn't deduce the right version. Here is an example:
template<typename T>
class Iterator
{
public:
Iterator() {}
};
template<typename T>
class ConstIterator
{
public:
ConstIterator() {}
};
template <typename T>
class MyList {
public:
MyList() {}
Iterator<T> Begin()
{
return Iterator<T>();
}
ConstIterator<T> Begin() const
{
return Iterator<T>();
}
void Insert(ConstIterator<T> it)
{
}
};
int main() {
MyList<int> myList;
myList.Insert(myList.Begin());
}
At myList.Insert(myList.Begin()); it does not try to use the correct version of Begin(), the const one.
From what I can tell in the std::vector implementation, there are two versions of begin() - one returns an iterator and one returns a const_iterator. The only other difference between them is that one is a const method (the one returning a const_iterator).
_NODISCARD _CONSTEXPR20 iterator begin() noexcept {
auto& _My_data = _Mypair._Myval2;
return iterator(_My_data._Myfirst, _STD addressof(_My_data));
}
_NODISCARD _CONSTEXPR20 const_iterator begin() const noexcept {
auto& _My_data = _Mypair._Myval2;
return const_iterator(_My_data._Myfirst, _STD addressof(_My_data));
}
Many methods, like std::vector::insert take a const_iterator parameter:
_CONSTEXPR20 iterator insert(const_iterator _Where, const _Ty& _Val) { // insert _Val at _Where
return emplace(_Where, _Val);
}
_CONSTEXPR20 iterator insert(const_iterator _Where, _Ty&& _Val) { // insert by moving _Val at _Where
return emplace(_Where, _STD move(_Val));
}
However, there is nothing in the insert method that would make the compiler use the const version of begin().
Which means it has to deduce by the return type alone, but as far as I know that's not possible?
How is it achieving it then?
There is no deduction. If myList is not const-qualified, then the non-const version of Begin() is called for myList.Begin(). Otherwise the const version is called. How you use the result of myList.Begin() is not relevant.
The standard library avoids your issue by providing a conversion from the non-const iterator to the const iterator. For example you could give ConstIterator a constructor which accepts a Iterator, which you must have anyway to make the return Iterator<T>(); statement in your const version of Begin() work (assuming that is not a typo).
I'm trying to implement a vector(just like the one in STL).
Here is part of my code
template <class T, class alloc>
class vector
{
public:
typedef T value_type;
typedef const value_type * const_iterator;
typedef value_type * iterator;
iterator start;
iterator finish;
iterator end_of_storage;
iterator begin() {return start;}
iterator end() {return finish;}
...
}
And when I'm trying compile codes below
vector<char> characters(2, 2);
cout << *++(characters.begin()) << endl;
Here comes the error
error: lvalue required as increment operand
I'm not sure what happened, I think characters.begin() should be a lvalue. I've looked at the one in SGI STL and I couldn't find anything.
Many thanks for any advice.
This issue arises because you are using raw pointers as iterators. When you return a raw pointer (or other primitive type, such as int) from function it is not a modifiable value. However it can be easily fixed by using class iterator:
template<typename T>
struct base_iterator
{
T * m_p_value;
base_iterator &
operator ++(void)
{
++m_p_value;
return *this;
}
T &
operator *(void)
{
return *m_p_value;
}
};
// inside of vector
typedef base_iterator< value_type > iterator;
online compiler
I'm taking a course where we're being introduced to a few software patterns, one of them being the iterator pattern, and we're being asked to implement it in C++. Our professor gave us some sample code a few weeks ago and I'd like to understand it a little better than I do. First I'll post the code:
template <class T_,std::size_t SIZE_>
class carray {
public:
typedef T_ value_type;
typedef std::size_t size_type;
typedef T_ & reference;
typedef T_ const & const_reference;
typedef T_ * pointer;
typedef T_ const * const_pointer;
typedef T_ * iterator;
typedef T_ const * const_iterator;
typedef std::ptrdiff_t difference_type;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
// data store
value_type data[SIZE_];
size_type size() const { return SIZE_; }
reference operator [] ( size_type idx ) { return data[idx]; }
const_reference operator [] ( size_type idx ) const { return data[idx]; }
reverse_iterator rbegin() { return reverse_iterator( end() ); }
reverse_iterator rend() { return reverse_iterator( begin() ); }
const_reverse_iterator rbegin() const { return const_reverse_iterator( end() ); }
const_reverse_iterator rend() const { return const_reverse_iterator( begin() ); }
const_reverse_iterator crbegin() const { return const_reverse_iterator( end() ); }
const_reverse_iterator crend() const { return const_reverse_iterator( begin() ); }
iterator begin() { return data; }
iterator end() { return data + SIZE_; }
const_iterator begin() const { return data; }
const_iterator end() const { return data + SIZE_; }
const_iterator cbegin() const { return data; }
const_iterator cend() const { return data + SIZE_; }
};
In this template our prof defined a bunch of typedefs, and a few of them had both a non-constant and constant version. First, I wonder what the purpose of each of the public members are, and second, I wonder what the purpose of the constant versions are, in the context of defining a data structure template.
I also notice that some of the member functions are defined as 'const' and I wonder what the purpose of that is.
I wonder what the purpose of each of the public members are.
The class contains the following:
Type aliases: Type information that is exposed from the class for public use.
The non-const typedefs are type aliases for a non-const T.
The const typedefs are type aliases for a const T.
These typedefs are useful because the user of the class might need more information about the type. By using the typedef exposed by the class, he can obtain this. Here's a good example - Consider the situation where we have a template type and we need to access the underlying iterator type. By using the exposed type alias, we can access it:
template<class Container>
void example(Container& c)
{
typename Container::iterator begin = c.begin(),
// ^^^^^^^^^^^^^^^^^^^
end = c.end();
}
I wonder what the purpose of the constant versions are.
Sometimes the user needs to use const types. Therefore using the type information that class provides makes this simple.
I also notice that some of the member functions are defined as 'const' and I wonder what the purpose of that is.
const member functions are functions that do not modify any of the classes data members.
all the typedefs aim to facilitate the use of these types,
std::size_t std::ptrdiff_t is just unsigned int typedefs.
chech here for reverse_iterator
const varialbe defined for the return value of the const version function, which is provided for the const obj, check here
member function defined as const make sure the member variable is not changed in the function body, check here
For this, I think you should try to use this template, and you may really know why it need such public members.
while we are using this template to operate on some data structure, if we want to modify some data, we need a non-constant version. On the other side, if we want to change the value of data, we need a constant version which can help us protect data.
Constant functions can help you, while you are trying to operate on some data and you do not want to modify the member data.
I have a template based custom collection (as we cannot use std::vector on the interface). I would like to implement a reverse_iterator specific to this collection. The reverse iterator struct below is a structure nested within the collection class. An iterator (basically a pointer to element type of the collection) is already implemented. This is my first attempt at a reverse iterator.
template <typename T>
struct reverse_iterator
{
typedef T::iterator iterator;
typedef T& reference;
inline reverse_iterator(const iterator & it):_it(it){}
inline reverse_iterator() : _it(0x0) {}
inline iterator base() const {iterator it = _it; return --it;}
inline reverse_iterator operator ++ () {return reverse_iterator(--_it);}
inline reverse_iterator operator -- () {return reverse_iterator(++_it);}
inline reverse_iterator operator ++ (int val) {_it -= val; return reverse_iterator(_it);}
inline reverse_iterator operator -- (int val) {_it += val; return reverse_iterator(_it);}
inline reverse_iterator operator += (int val) {_it -= val; return reverse_iterator(_it);}
inline reverse_iterator operator -= (int val) {_it += val; return reverse_iterator(_it);}
inline reverse_iterator operator + (int val) const {iterator it = _it - val; return reverse_iterator(it);}
inline reverse_iterator operator - (int val) const {iterator it = _it + val; return reverse_iterator(it);}
bool operator == (const iterator & other) const {return other == base();}
bool operator != (const iterator & other) const {return other != base();}
reference operator*() const {return *base();}
iterator operator->() const {return base();}
private:
iterator _it;
};
Is this is workable reverse_iterator or am I missing something ?
Can this be improved?
Except for the things mentioned below your implementation is almost the same as the implementation in libstdc++ (v3, but still somewhat accurate). Note that you're currently missing all non-member functions. All in all you should try to match the std::reverse_iterator interface: if you're ever able to use std types you can happily exchange your mylab::reverse_iterator by std::reverse_iterator.
Missing things
You're missing all comparison operators between reverse_iterator, such as operator==, operator!=, operator< and so on.
Strange things
This is basically a list of stuff where your reverse_iterator differs from the standard one.
Usually the pre-increment/-decrement operators return a reference (*this) and not a new object.
The post increment/decrement operators shouldn't take a value:
inline reverse_iterator operator ++ (int) {
reverse_iterator tmp = *this;
++*this; // implement post-increment in terms of pre-increment!
// or --_it;
return tmp;
}
inline reverse_iterator operator -- (int) { ... }
The compound assignment operators also usually return references.
Your const iterator& constructor should be explicit, otherwise one could accidentally mix reverse and normal iterators.
Instead of a container type T you should use the underlying iterator as template parameter:
template <typename Iterator>
struct reverse_iterator
{
typedef Iterator iterator;
typedef typename iterator_traits<Iterator>::reference reference;
...
}
This enables you to use reverse_iterator on anything that iterator_traits can handle:
template <class Iterator>
struct iterator_traits{
typedef typename Iterator::reference reference;
// Add other things
};
template <class T>
struct iterator_traits<T*>{
typedef T & reference;
};
With this you can even use reverse_iterator<int *> or similar.
operator-> usually returns a pointer to the underlying object, not an intermediary iterator. You might want to add a pointer typedef to both your traits and your original iterator.
It's very uncommon to check equality between different types. Remove the operator==(const iterator&).
I'm trying to implement a reverse-iterator adaptor for my iterator and const_iterator classes with a little bit of trouble. If anyone could guide me through this, that would be greatly appreciated!
The idea is that I should be able to create a reverse-iterator from my rbegin() and rend() function calls
reverse_iterator rbegin();
reverse_iterator rend();
const_reverse_iterator rbegin() const;
const_reverse_iterator rend() const;
I'm using the following typedef's in the class:
typedef btree_iterator<T> iterator;
typedef const_btree_iterator<T> const_iterator;
typedef reverse_btree_iterator<iterator> reverse_iterator;
typedef reverse_btree_iterator<const_iterator> const_reverse_iterator;
As you can see, I would like to be able to create reverse-iterators using templates, giving the reverse_iterator class either an iterator or const_iterator.
Unfortunately, it is this bit I'm stuck on...
Below is the class definition that I currently have, with errors.
template <typename I> class reverse_btree_iterator {
typedef ptrdiff_t difference_type;
typedef bidirectional_iterator_tag iterator_category;
public:
reverse_btree_iterator() : base_(I()) {}
template <typename T> reverse_btree_iterator(const btree_iterator<T>& rhs) : base_(rhs) {}
I base() { return base_; }
I::reference operator*() const;
I::pointer operator->() const;
I& operator++();
I operator++(int);
I& operator--();
I operator--(int);
bool operator==(const I& other) const;
bool operator!=(const I& other) const;
private:
I base_;
};
I've never used templates like this before, so it is very likely I'm completely misunderstanding how they can be used...
Since I can be an iterator or a const_iterator, the typedef of reference and pointer vary between the two classes. The lines that aren't compiling are these:
I::reference operator*() const;
I::pointer operator->() const;
I'm not sure how else I can make the one reverse_iterator class work for both iterator and const_iterator if I'm not able to do I::reference and I::pointer. I also tried adding template in front of those, since they are defined in the iterator class (for example) as:
typedef T* pointer;
typedef T& reference;
reference and pointer are dependent names, so you have to use
typename I::reference operator*() const;
typename I::pointer operator->() const;
In addition, the constructor should accept just the I.
However, there is no need to write this class at all. The standard library has reverse_iterator for this. Or if you are not happy with that, there's also Boost.ReverseIterator.
All it takes is just
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
In addition, you forgot to provide comparison operators with other reverse iterators of the same type. This is a reverse iterator requirement.