Reputation:
How is the before_begin
method implemented in the context of a std::forward_list
?
I have tried something like this:
template <class _Tp>
typename forward_list<_Tp>::iterator forward_list<_Tp>::before_begin() NOEXCEPT {
return forward_list_iterator<_Tp>(new forward_list_node<_Tp>(_Tp(), m_pHead));
}
template <class _Tp>
typename forward_list<_Tp>::const_iterator forward_list<_Tp>::before_begin() const NOEXCEPT {
return forward_list_const_iterator<_Tp>(new forward_list_node<_Tp>(_Tp(), m_pHead));
}
What I understood is that the before_begin
method shall be used when calling insert_after
emplace_after
etc. Thus I made the method return an iterator
to a new node that points to m_pHead
and has a default value for the template type _Tp
. However, I am unsure about two things:
1) As I am using templates, how can I get the default value? Is _Tp()
a legal expression in order to get the default value for the specific type (with both primitive and user-defined types)?
2) As this method returns an iterator
before m_pHead
, if I call one of the insert_after
overloaded methods with before_begin
as the first argument, wouldn't I end up having the data inserted in the list, but without having the m_pHead
updated?
My implementation of (one of the four overloads of) insert_after
is as follows:
template <class _Tp>
void forward_list<_Tp>::insert_after(const_iterator _position, const _Tp& _value) {
forward_list_node<_Tp>* _node = new forward_list_node<_Tp>(_value, _position.m_pNode->m_pNext);
_position.m_pNode->m_pNext = _node;
}
Thank you very much for taking your time. :)
EDIT: According to the code in the link from T.C.'s answer, the before_begin
should be implemented like this:
iterator before_begin() { return iterator(&head); }
However, this is how my begin
is implemented:
template <class _Tp>
typename forward_list<_Tp>::iterator forward_list<_Tp>::begin() NOEXCEPT {
return forward_list_iterator<_Tp>(m_pHead);
}
I don't really get how the before_begin
implementation above should work (either that, or my insert_after
is not written correctly).
EDIT 2: From what I understand so far, the before_begin
should return the m_pHead
and the begin
should return m_pHead->m_pNext
.. That doesn't really make much sense, as begin
should implicitly refer to m_pHead
, but it is a workaround I guess.
Upvotes: 0
Views: 1000
Reputation: 137310
The basic idea is this:
struct node_base {
node_base * next;
};
template<class T>
struct node : node_base {
T value;
};
template<class T>
struct forward_list_iter {
forward_list_iter(node_base *pn) : pnode(pn) { }
T& operator*() const { return static_cast<node<T>*>(pnode)->value; }
forward_list_iter& operator++() { pnode = pnode->next; return *this; }
// other stuff
node_base* pnode;
};
template<class T>
struct forward_list {
node_base head;
forward_list_iter<T> before_begin() {
return forward_list_iter<T>(&head);
}
forward_list_iter<T> begin() {
return forward_list_iter<T>(head.next);
}
// other stuff
};
The head
node is embedded in the forward_list
itself, and is just a node_base
, which just contains just a pointer to the next node. All other nodes are actually node<T>
s, which derive from node_base
and stores a value of type T
. The iterator stores a node_base *
, and casts it to a node<T> *
when dereferenced. before_begin()
points to head
; begin()
points to head.next
, which is actually the first node to contain a value.
Upvotes: 4