I've been attempting to overload the ++ operator to move an iterator through a list, but I keep getting Error C2460 'List::Iterator::++': uses 'List::Iterator'
template <typename E>
class List : public SLinkedList<E> {
public:
// NOTE THE DIFFERENT LETTER – IT IS ONLY USED HERE!
// Use E everywhere else! m
// For a nested class, methods are declared and defined *INSIDE*
// the class declaration.
template <typename I>
class Iterator {
public:
// Give List access to Iterator private fields.
friend class List<E>;
// These are the minimum methods needed.
E operator* {nodePosition->elem}; //dereference the iterator and return a value
Iterator<E> operator++ {nodePosition = nodePosition->next}; //increment the iterator
Iterator<E> operator-- {
nodePosition = nodePosition->prev;
} //decrement the iterator
bool operator==(const Iterator<E> p) {
return (nodePosition == p)
} //test equality of iterators
bool operator!=(const Iterator<E> p) {
return (nodePosition != p)
} //test inequality of iterators
private:
// Constructors & destructor here since only want List class to access.
// List constructor called from List::begin(). Use initializer list or
// create class copy constructor and assignment overload.
Iterator(const List<E>* sl) : llist(sl) {
nodePosition = sl->head;
}
// Class fields.
const List<E>* llist; //give Iterator class a handle to the list
Node<E>* nodePosition; //abstracted position is a pointer to a node
}; /** end Iterator class **/
/* The Iterator class is now fully defined. The rest of these
statements must go AFTER the Iterator class or the compiler
won’t have complete information about their data types.
*/
// REQUIRED: While not necessary for the code to work, my test suite needs
// this defined. Create a less cumbersome name for Iterator<E>. Use
// anywhere you would have used List<E>::Iterator<E> in class List. Allows
// this syntax in main() -- List<int>::iterator instead of List<int>::Iterator<int>.
typedef typename List<E>::Iterator<E> iterator;
/*** All method declarations and fields for the List class go here.
Any method that returns an iterator must be defined here.
***/
iterator begin() const { //return an iterator of beginning of list
// Call iterator constructor with pointer to List that begin() was
// called with.
return iterator(this);
}
E back();
E pop_back();
void push_back(const E e);
}; /** end List class declaration **/
The following method definitions are malformed:
E operator* {nodePosition->elem}; //dereference the iterator and return a value
Iterator<E> operator++ {nodePosition = nodePosition->next}; //increment the iterator
Iterator<E> operator-- {
nodePosition = nodePosition->prev;
} //decrement the iterator
Even though none of these methods need parameters, the () is still required. The compiler is probably seeing them as variable definitions of some sort and letting things continue long enough to get the error message OP is reporting.
E operator*() {nodePosition->elem}; //dereference the iterator and return a value
Iterator<E> operator++() {nodePosition = nodePosition->next}; //increment the iterator
Iterator<E> operator--() {
nodePosition = nodePosition->prev;
} //decrement the iterator
They are also all state that they return a value, but none of the function bodies do. There is a lot more work required here before this code will function.
Related
What I want to achieve is probably easily explained: Consider I have an abstract class that I know will contain multiple objects of known type. However the actual container holding these objects will be implemented in sub-classes.
In my abstract base class I now want to provide an interface to iterate over these objects. Given that I don't know (or rather don't want to fix) the type of container, I thought that iterators would probably be my best bet.
A conceptual declaration of this class might look like this:
class MyClass {
public:
// Other interface methods, e.g. size()
virtual Iterable<MyObject> objects() = 0;
};
The intention here is that I'll be able to iterate over the nested objects of my class like this:
MyClass *class = new ImplementationOfClass();
for (const MyObject &obj : class->objects()) {
// Do stuff with obj
}
The issue I am facing however is that I can't seem to figure out how Iterable<MyObject> should be defined. The key property of this object is that at the time of defining this class I can only specify that the returned value will be iterable (using STL-style iterators) and will yield objects of type MyObject when the used iterator is dereferenced.
Normally I would use an abstract class on its own for this but it seems that this is very tricky (impossible?) since iterators are always passed by value and thus to my knowledge no Polymorphism is possible.
Questions dealing with how to pass arbitrary iterator types as arguments into a function always come up with the "use templates" answer. However I think in my case I can't use templates for that. This assumption might be wrong though, so feel free to correct me.
Essentially the barrier I always run into is that at some point I have to write down the iterator type explicitly which in my case I can't. I thought about using a template for that but this would then inhibit proper Polymorphism (I think?) because the user of that abstract interface seems to have the burden of explicitly initializing the correct template. The whole point of all of this however is that the caller does not have to care about the underlying structure.
TL;DR: Is there a way to create an interface class that only promises to be iterable and that dereferencing an iterator will yield an object of type T?
With the help of #FrançoisAndrieux and a hint from https://stackoverflow.com/a/4247445/3907364, I was able to come up with an approach to my problem.
Essentially the idea is to create an iterator-wrapper that stores a function to obtain an object of the given type if given an index. That index is then what is iterated on.
The nice thing about this is that the iterator interface is fixed by specifying the type of object that dereferencing it should return. The polymorphism comes into play by making the member function objects() virtual so that each sub-class can construct the iterator itself, providing a custom function pointer. Thus as long as there is a way to map an index to the respective element in the container (whichever is used), this trick is usable.
Note that you can either directly use pointers to e.g.std::vector<T>::at or create a custom function that will return the respective element.
Here's the implementation for the iterator (The implementation could probably be improved upon but it seems to get the job done):
template< typename T > struct iterator_impl {
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = T *;
using reference = T &;
using access_function_t = std::function< T &(std::size_t) >;
// regular Ctor
iterator_impl(std::size_t start, access_function_t &func, const void *id)
: m_index(start), m_func(func), m_id(id) {}
// function-move Ctor
iterator_impl(std::size_t start, access_function_t &&func, const void *id)
: m_index(start), m_func(func), m_id(id) {}
// copy Ctor
iterator_impl(const iterator_impl &) = default;
// move ctor
iterator_impl(iterator_impl &&other) {
std::swap(m_index, other.m_index);
m_func = std::move(other.m_func);
std::swap(m_id, other.m_id);
}
// copy-assignment
iterator_impl &operator=(const iterator_impl &other) = default;
// prefix-increment
iterator_impl &operator++() {
++m_index;
return *this;
}
// postfix-increment
iterator_impl operator++(int) {
iterator_impl old = *this;
++(*this);
return old;
}
bool operator==(const iterator_impl &other) { return m_index == other.m_index && m_id == other.m_id; }
bool operator!=(const iterator_impl &other) { return !(*this == other); }
T &operator*() { return m_func(m_index); }
T *operator->() { return &m_func(m_index); };
protected:
std::size_t m_index = 0;
access_function_t m_func;
const void *m_id = nullptr;
};
Note that I had to introduce the m_id member variable as a means to properly compare iterators (std::function can't be compared using ==). it is meant to be e.g. the address of the container the elements are contained in. Its sole purpose is to make sure that 2 iterators that happen to have the same index but are iterating over completely different sets are not considered equal.
And based on that here's an implementation of an Iterable<T>:
template< typename T > struct Iterable {
using iterator = iterator_impl< T >;
using const_iterator = iterator_impl< const std::remove_const_t< T > >;
Iterable(std::size_t start, std::size_t end, typename iterator_impl< T >::access_function_t &func, const void *id)
: m_begin(start, func, id), m_end(end, func, id) {}
iterator begin() { return m_begin; }
iterator end() { return m_end; }
const_iterator begin() const { return m_begin; }
const_iterator end() const { return m_end; }
const_iterator cbegin() const { return m_begin; }
const_iterator cend() const { return m_end; }
protected:
iterator m_begin;
iterator m_end;
};
OK, this one has me stumped. Clearly I've missed something, so I hope someone can tell me what it is.
I'm developing a C++17 library. I've written a custom tree data structure composed of Node objects and a custom iterator, Node::iterator, for traversing the tree. The iterator looks like this:
template <typename T>
class NodeIterator {
public:
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = std::shared_ptr<T>;
using reference = T&;
using iterator_category = std::forward_iterator_tag;
NodeIterator() = default;
NodeIterator(pointer n);
// Etc.
}
And later...
template class NodeIterator<Node>;
template class NodeIterator<const Node>;
When I add the standard iterator methods (begin(), end(), and the const equivalents) to a parent class Tree, I can control the initial value for the iterator. So I can say
Node::iterator Tree::begin() const {
return Node::iterator(_root);
}
where _root is a std::shared_ptr<Node>. This works great.
However, not content to leave well enough alone, I want these iterator methods on the node itself. That way I can traverse a subtree from any node, eliminate the Tree class altogether, and just pass around Node objects.
I declare Node as
class Node : public std::enable_shared_from_this<Node> {
public:
using iterator = NodeIterator<Node>;
using const_iterator = NodeIterator<const Node>;
iterator begin() const;
iterator end() const;
const_iterator cbegin() const;
const_iterator cend() const;
// Etc.
}
and define the iterator methods as
Node::iterator Node::begin() const {
return Node::iterator(this->shared_from_this());
}
Node::iterator Node::end() const {
return Node::iterator(nullptr);
}
Node::const_iterator Node::cbegin() const {
return Node::const_iterator(this->shared_from_this());
}
Node::const_iterator Node::cend() const {
return Node::const_iterator(nullptr);
}
The compiler then loudly complains about the return statement:
src/node.cc:79:9: error: no matching conversion for functional-style cast from
'shared_ptr<const Node>' to 'Node::iterator' (aka 'NodeIterator<Node>')
return Node::iterator(this->shared_from_this());
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
and later...
include/example.h:344:2: note: candidate constructor not viable: no known
conversion from 'shared_ptr<const Node>' to 'shared_ptr<Node>' for
1st argument
NodeIterator(pointer n);
^
In another method, Node::appendChild(), I automatically set the parent node (std::shared_ptr<Node>) to this->shared_from_this(), and it works fine.
If I comment out Node::begin() and Node::end() and only use cbegin() and cend() in my loop, it also works fine.
What gives?
shared_from_this has const and non-const overloads. See cppreference. Within your const begin, this is pointer to const and calls the const overload which returns a shared_ptr to const.
I faced a problem of overloading the ->() operator while implementing the Iterator class. How should this operator be overloaded?
class iterator
{
private:
pair<Key_t, Val_t> p;
public:
iterator()
{
}
iterator(const iterator &i)
{
p = i.p;
}
iterator(Key_t key, Val_t v)
{
p = make_pair(key,v);
}
pair<const Key_t,Val_t>& operator *() const
{
return p;
}
iterator& operator = (const iterator &iter)
{
this->p = iter;
return *this;
}
};
tried this way unsuccessfully
&(pair<const Key_t,Val_t>&) operator ->() const
{
return &(**this);
}
This whole approach looks wrong.
An iterator isn't supposed to contain a value, it's supposed to contain at least
The information necessary to locate a value inside the container.
Information necessary to traverse to the next element within the container.
By storing a value inside the iterator, you cause unnecessary copies and lose the ability to update the container (change the value, remove the element from the container, etc).
For example, an iterator for a std::vector-like container might store a handle to the container and the index (offset) to the current item.
The only time an iterator would have a value itself is when you're implementing a generator that isn't actually associated with a container.
I wish to define an iterator class over a vector, and how can its private member p match the return type of std::vector::begin()?
class A{
struct element{
...
}
class e_iterator {
e_iterator() : p()
...
private:
element* p;
};
e_iterator e_begin() const{
e_iterator Iter;
Iter.p = e_.begin(); // error
return Iter;
}
std::vector<element> e_;
}
I receive an error with element* p:
error: cannot convert 'std::vector<element, std::allocator<element>>::const_iterator' to 'element*' in assignment
With what you've given, the most I can suggest is changing p to:
std::vector<element>::const_iterator p;
The simple fact is that a std::vector iterator is not a pointer (probably). It is an unspecified type that behaves like a pointer - it meets the requirements of a Random Access Iterator.
When you call begin() on a non-const container, you get an iterator type. When you call it on a const iterator, you get a const_iterator type. Since your a_begin member function is marked const and e_ appears to be a std::vector<element> member of your class, e_ is transitively const, so calling begin() on it will also get you a const_iterator.
But it's quite hard to tell exactly what you're trying to do here and whether this is the right way to go about it.
Either change element* p to const element* p in your iterator class or remove the const qualifier from your e_begin() method.
Or provide both const/non-const iterator. I also suggest to initialize the pointer in the iterator constructor:
template <bool isconst>
class e_iterator_ {
public:
typedef std::conditional<isconst, const element*, element*>::type elementptr;
e_iterator_(elementptr e) : p(e)
...
private:
elementptr p;
};
typedef e_iterator_<true> const_e_iterator;
typedef e_iterator_<false> e_iterator;
Then you could use the data() member method of std::vector to directly access the underlying array of the vector.
e_iterator e_begin() const{
const_e_iterator Iter(e_.data());
return Iter;
}
Hope this helps.
I have an iterator which iterates over a std::shared_ptr. So operator++ points the internally stored shared pointer to the next item.
template<class IT>
class MyIterator
{
public:
...
MyIterator& operator++()
{
_i = ... // Call factory
return *this;
}
private:
std::shared_ptr<IT> _i;
};
How should I implement the operator*() and operator->() operators?
How should I test if the iterator is pointing to NULL, i.e. if the internal shared pointer is pointing to NULL.
You should define under what circumstances users are permitted to deference an instance of your class. Usually this is "anything other than an end iterator or an uninitialized iterator".
Then you should ensure that _i never contains a null pointer for an instance that can be dereferenced.
This means there is no need for a check, because the user is not permitted to call operator* or operator-> in that circumstance. You could add one for debugging, for example: assert(_i.get());.
You don't specify what the value_type is of your iterator, but assuming that it is IT, you can implement:
IT &operator*() { return *_i; }
shared_ptr<IT> operator->() { return _i; }
// or
IT *operator->() { return _i.get(); }