I need an intrusive, sorted, double-linked list. I do not want to use boost::intrusive, so I'm doing this myself and running into an issue
For a doubly-linked list there are several operations, here is just one of them which will help to illustrate my point:
template<typename LIST, typename NODE>
void insertAfter(LIST *list, NODE *node, NODE *newNode)
{
newNode->prev_ = node;
newNode->next_ = node->next_;
if(nullptr == node->next_)
list->last_ = newNode;
else
node->next_->prev_ = newNode;
node->next_ = newNode;
}
Now suppose I have a set of objects that are in one such list BUT I want their guts private:
struct Object
{
private:
Object *prev_, *next_;
};
Now I create my List (please ignore the fact that when the list is empty there will be a nullptr exception...).
struct List
{
Object *first_, *last_;
void addObject(Object *o)
{
insertAfter(this, last_, o); // not correct when list empty
}
};
This will not compile because prev_ and next_ are private and insertAfter does not have access. It can be solved easily with this:
// Fwd decl
struct List;
struct Object
{
friend void insertAfter<List, Object>(List *, Object *, Object *);
private:
Object *prev_, *next_;
};
struct List
{
Object *first_, *last_;
void addObject(Object *o)
{
insertAfter(this, last_, o);
}
};
But this opens an access hole such that anyone can use insertAfter to affect Object's private members. What I really want is for List to be a friend of Object. I could solve this by not using templates for my linked list operation (use plain macros instead) but this obviously has its downside. What's the right way to go here?
How about something along these lines?
I can't see how it's really less offensive than what you've been doing already, though: template code is inline anyway, so you can't stop people from rewriting your class to their liking. Just relax and have reasonable degree of trust in your clients :)