Reputation: 10425
So I have a very dumbed down example of a singly-linked list implementation. And I have a begin
function as a public member of the forward_list
which returns a pointer to the first (root) element of the list.
Now since it returns a pointer to a _node
object which contains various members, it is to my understanding that a dereference operator overload must be provided in order for _node
to know what to return when dereferenced.
In the dereference operator definition I tried returning the value
of the _node
, which all seems quite logical, since begin
returns a _node
that would mean dereferencing begin
would give me the value
behind the _node
. Apparently not, as the MSVC compiler tells me: binary '<<': no operator found which takes a right-hand operand of type '_node<TType>' (or there is no acceptable conversion)
#include <iostream>
#include <cstddef>
//forward declarations
template<class TType> class forward_list;
template<class TType>
class _node
{
private:
TType key;
_node *next;
friend class forward_list<TType>;
public:
TType operator*() { return this->key; } //problem is here
};
template<class TType>
class forward_list
{
private:
_node<TType> *_root;
_node<TType> *_tail;
std::size_t _size;
private:
void _add_node_front(const TType &new_key)
{
_node<TType> *new_node = new _node<TType>{ new_key, this->_root };
if (this->_root == nullptr)
this->_tail = new_node;
this->_root = new_node;
++this->_size;
}
public:
forward_list() : _root(nullptr), _tail(nullptr), _size(0) {}
void push_front(const TType &new_key) { this->_add_node_front(new_key); }
_node<TType> *begin() { return this->_root; }
};
int main()
{
forward_list<int> l;
l.push_front(23);
l.push_front(57);
l.push_front(26); //26 57 23
std::cout << *l.begin(); //expected to print out "26"
}
EDIT:: Thanks to Joachim Pileborg for suggesting. Works like a charm with the following change:
_node<TType> begin() { return *this->_root; }
Upvotes: 1
Views: 676
Reputation: 120031
The immediate reason of thee error is that begin
returns a _node*
, and your overloaded operator*
needs a _node
.
If you want to implement a standard-conforming container, your begin
operator should return an iterator (by value), not a (pointer to a) node. This iterator thing should implement operator*
(and also operator++
and a bunch of other stuff). The node class is not suitable as an iterator. You need a separate class. Google something like "implementing my own iterators".
If you implement iterators, don't expose your node class to end users.
If you want just any list that doesn't conform to anything in particular, you will probably be better off not overloading any operators. Use getValue
or something.
Upvotes: 2
Reputation: 19607
You are returning a pointer:
_node<TType> *begin();
so you need to dereference that twice:
_node<...>
, not for _node<...> *
, it won't be called instead of the simple dereference)Perhaps, a better would be to replace
TType operator*();
with user defined conversions, which will return this->key;
:
operator TType& ();
operator TType const& () const;
and you won't need that second dereference.
Upvotes: 2
Reputation: 419
The problem is on this line:
std::cout << *l.begin(); //expected to print out "26"
You haven't defined operator<< to stream one of these objects to an ostream.
Upvotes: 0
Reputation: 409364
The problem is that you dereference the pointer which gives you an object of type _node<int>
which you can then again use the dereference operator on.
So you could solve your problem by using two dereference operators:
**i.begin()
Another solution is that you return the node by value instead of returning a pointer to it, which is how iterators functions in the standard containers.
Upvotes: 1