Ivaylo Valchev
Ivaylo Valchev

Reputation: 10425

Dereference operator doesn't work (syntax issue?)

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

Answers (4)

n. m. could be an AI
n. m. could be an AI

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

LogicStuff
LogicStuff

Reputation: 19607

You are returning a pointer:

_node<TType> *begin();

so you need to dereference that twice:

  1. dereference the pointer
  2. call your operator (it's defined for _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

stiabhan
stiabhan

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

Some programmer dude
Some programmer dude

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

Related Questions