BST with function ptr, How to add in extra argument? - c++

is there a way to pass in an extra argument to my function pointer in BST? I am trying to use BST inOrder to get value from a map<string, int>. this BST will be storing the key of the map.
The map will act as a database that uses date + time as the key. each BST will be created to store the date+time of each year and saved into another map (bstMap) which holds all bst. bstMap will use the year as key.
BST inOrder with function ptr.
#ifndef BST_H
#define BST_H
#include<iostream>
using namespace std;
template <class T>
class Node.
{
public:
T m_key;
Node<T> *m_left;
Node<T> *m_right;
};
template <class T>
class BST
{
typedef void(*funcPtr)(T &);
public:
BST();
void Insert(T key);
void Delete();
void InOrder(void(*funcPtr)(T &)) const;
void PreOrder(void(*funcPtr)(T &)) const;
bool Search(T key);
T MaxValue();
bool IsEmpty() const {return m_root == nullptr;}
void DeleteTree();
private:
Node<T> *m_root;
protected:
Node<T> *Insert(Node<T>* node, T key);
Node<T> *Search(Node<T>* node, T key);
void InOrder(Node<T>* node, void (*funcPtr)(T &)) const;
void PreOrder(Node<T>* node, void (*funcPtr)(T &)) const;
void DeleteTree(Node<T>* node);
Node<T>* MaxValue(Node<T>* node);
};
template<class T>
BST<T>::BST(){
m_root = nullptr;
}
template<class T>
void BST<T>::InOrder(Node<T>* node, void(*funcPtr)(T &)) const
{
if (node != nullptr)
{
InOrder(node-> m_left, funcPtr); //recursive call for node left
funcPtr(node-> m_key);
InOrder(node->m_right, funcPtr);
}
}
template<class T>
void BST<T>::InOrder(void(*funcPtr)(T &)){
InOrder(m_root, funcPtr);
}
This line of code is called from main.cpp which pass the user input year into the map to return the bst which stores all relevant keys.
void GetData(string& year, map<string, BST<string>>& bstMap)
{
BST<string> bstKey = bstMap[year];
bstKey.InOrder(&GetTotal);
}
So here is where i am stuck..
void GetTotal(string& key) <- how do i reference my database map here?
{
cout<< key <<endl;
}

If you want to access variables outside of the BST template class (such as the map), then I advise changing your template to the following (assuming that m_root is a member variable of BST<T>, and that it is the root of tree):
template<class T, class Fn>
void BST<T>::InOrder(Fn funcPtr) const
{
InOrder(m_root, fn);
}
template<class T, class Fn>
void BST<T>::InOrder(Node<T>* node, Fn funcPtr) const
{
if (node)
{
InOrder(node-> m_left, funcPtr); //recursive call for node left
funcPtr(node-> m_key);
InOrder(node->m_right, funcPtr);
}
}
Then this way, you can pass a function object or lambda that knows about the map. In the case below, a lambda function is used:
void GetData(string& year, map<string, BST<string>>& bstMap)
{
BST<string> bstKey = bstMap[year];
bstKey.InOrder([&](std::string& key) { std::cout << bstMap[key] << "\n"; });
}
The above provides a lambda that captures the passed-in map parameter.

Related

I'm trying to make a function "InOrder", which does inorder traversing in Binary Search

I'm trying to make InOrder in void-type, which executes in-order traversal in a binary search tree.
//Code Provided by Professor
//Program 5.1:Inorder traversal of a binary tree
//===============================================
template <class T>
void Tree<T>::Inorder()
{// Driver.
Inorder(root);
}
template <class T>
void Tree<T>::Inorder(TreeNode<T> *currentNode)
{// Workhorse.
if (currentNode) {
Inorder(currentNode->leftChild);
Visit(currentNode);
Inorder(currentNode->rightChild);
}
}
The above code is provided by Professor, as a reference making my own InOrder function.
This Code is how I declared the elements(requisites) for my binary search tree.
#include <iostream>
using namespace std;
template<class K, class E>
class BinarySearchTree
{
public:
virtual void Insert(const pair<K, E>&) = 0;
virtual void Delete(const K&) = 0;
virtual pair<K, E>*Get(const K&) const = 0;
virtual void InOrder()const;
};
template<class T>
struct TreeNode {
T data;
TreeNode<T> *leftChild;
TreeNode<T> *rightChild;
TreeNode(T node) : data(node), leftChild(0), rightChild(0) {}
};
template<class K, class E>
class BST : BinarySearchTree<K, E> {
public:
BST() : root(0) {}
void Insert(const pair<K, E>&);
void Delete(const K&);
pair<K, E>*Get(const K&)const;
void InOrder()const;
private:
TreeNode<pair<K, E>> *root;
};
Other functions work well, and I would appreciate any help with making InOrder function, using C++.
The concept of in order is just the concept of order. You must also say what should be done in that order. The code provided by your professor calls a visit function.
That means that in your implementation, you also need such a visit function. It can either be hardcoded (display a node on cout) or better passed as a parameter. In that case, you should declare InOrder as:
void InOrder(void (*visit)(const pair<K, E>&))const;
And later call it (for example with a lambda function) as:
BST<int, string> bst;
...
bst.InOrder([](const pair<int, string>&ke) {
cout << "K: " << ke.first << " -E: " << ke.second << "\n";
});
A possible implementation mimicing your professor's code could be:
template<class K, class E>
void BST<K,E>::doInOrder(const TN* root, void (*visit)(const pair<K, E>&)) {
if (root) {
doInOrder(root->leftChild, visit);
visit(root->data);
doInOrder(root->rightChild, visit);
}
}
template<class K, class E>
void BST<K,E>::InOrder(void (*visit)(const pair<K, E>&))const {
doInOrder(root, visit);
}

Accessing the left node with an iterator object in a Binary Search Tree

This is a function to find the maximum amount of left nodes. I do realize that there is already a thread for that:
Count number of left nodes in BST
but I don't want pointers in my main file. So I am trying to find a slightly different approach.
bst<int>::binTreeIterator it;
int findMax(bst<int>::binTreeIterator it)
{
int l = 0, r;
if (!(it.leftSide() == NULL)) {
l += 1 + findMax(it.leftSide());
}
if (!(it.rightSide() == NULL)) {
r = findMax(it.rightSide());
}
return l;
}
my problem is with the leftSide()/rightSide() function; How do I implement them so that it returns an iterator object that points to the left side/ right side of the iterator "it" object?
template <class Type>
typename bst<Type>::binTreeIterator bst<Type>::binTreeIterator::leftSide()
{
}
Edit:
template <class Type>
class bst
{
struct binTreeNode
{
binTreeNode * left;
binTreeNode * right;
Type item;
};
public:
class binTreeIterator
{
public:
friend class bst;
binTreeIterator();
binTreeIterator(binTreeNode*);
bool operator==(binTreeNode*);
bool operator==(binTreeIterator);
binTreeIterator rightSide();
binTreeIterator leftSide();
private:
binTreeNode * current;
};
bst();
bst(const bst<Type>&);
const bst& operator=(const bst<Type>&);
~bst();
void insert(const Type&);
void display(); // TEST
binTreeIterator begin();
binTreeIterator end();
private:
binTreeNode * insert(binTreeNode*, const Type&);
void inorder(binTreeNode*);
void destroyTree(binTreeNode*);
void cloneTree(binTreeNode*, binTreeNode*);
binTreeNode * root;
};
This very simple snipped of code should do the trick already:
template <class Type>
typename bst<Type>::binTreeIterator bst<Type>::binTreeIterator::leftSide()
{
return current->left;
}
As you did not declare the iterator's constructor explicit, it will get called automatically from the pointer to left/right returned.

how to write a default iterator to a generic list?

i am writing this code a generic list , now in this generic list i did a class for iterator that helds two parameters : one is a pointer to the list he points to .
and the other one points to the element in the list he points to ..
now i need to write an insert function that inserts a new element to a given list , with the following rules :: where i insert a new node to the list, and in this function if the iterator poiints to the end of the list the we add the new node to the end of the list else we insert the node one place before the node that the iterator currently points to , and if the iteratot points to a different node then thats an error .
now i want the iterator to be defoult so in case in the tests someone called the function with one parameter i want the iterator to be equal to the end element of the list.
the function end i wrote it inside of the list.
now in the insert function i did that but i get this error :
cannot call member function "List::iterator List::end()"without object
.
#include <iostream>
#include <assert.h>
#include "Exceptions.h"
template <class T>
class List {
public:
List();
List(const List&);
~List();
List<T>& operator=(const List& list);
template <class E>
class ListNode {
private:
ListNode(const E& t, ListNode<E> *next): data(new E(t)), next(next){}
~ListNode(){delete data;}
E* data;
ListNode<E> *next;
public:
friend class List<E>;
friend class Iterator;
E getData() const{
return *(this->data);
}
ListNode<E>* getNext() const{
return this->next;
}
};
class Iterator {
const List<T>* list;
int index;
ListNode<T>* current;
Iterator(const List<T>* list, int index): list(list),
index(index),current(NULL){
int cnt=index;
while (cnt > 0) {
current = current->next;
cnt--;
}
}
friend class List<T>;
friend class ListNode<T>;
public:
// more functions for iterator
};
Iterator begin() const ;
Iterator end() const;
void insert(const T& data, Iterator iterator=end());//here i get the error
void remove(Iterator iterator);
class Predicate{
private:
T target;
public:
Predicate(T i) : target(i) {}
bool operator()(const T& i) const {
return i == target;
}
};
Iterator find(const Predicate& predicate);
class Compare{
private:
T target;
public:
Compare(T i) : target(i) {}
bool operator()(const T& i) const {
return i < target;
}
};
bool empty() const;
int compareLinkedList(ListNode<T> *node1, ListNode<T> *node2);
private:
ListNode<T> *head;
ListNode<T> *tail;
int size;
};
any help would be amazing ! cause i don't know why such a mistake apears .
//insert function just in case :
template <typename T>
void List<T>::insert(const T& data, Iterator iterator=end()){
if(iterator.list!=this){
throw mtm::ListExceptions::ElementNotFound();
return;
}
ListNode<T> *newNode = new ListNode<T>(data, iterator.current);
if(iterator.index==size){
if (head == NULL) {
head = newNode;
tail=newNode;
}else{
Iterator temp(this,size-1);
temp.current->next=newNode;
}
//newNode->next=this->end().current;
}
else {
if (head == NULL) {
head = newNode;
tail=newNode;
}
else {
Iterator temp1(this,iterator.index-1);
temp1.current->next=newNode;
newNode->next=iterator.current->next;
}
}
size++;
}
void insert(const T& data, Iterator iterator=end());
This is the offending line. A default argument cannot be the result of a member function call. The right tool to achieve what you want is overloading.
void insert(const T& data, Iterator iterator);
void insert(const T& data) { insert(data, end()); }
Here we still defer to the insert function you implemented, but we call end from within the overloads body, where it's allowed.
Don't worry about the indirect call. This is a very small function that's defined inside the class declaration itself. Any decent compiler will inline it completely.

Double STL Linked List push_front error

I'm struggling with Implementing STL Double LinkedList. I'm almost a newbie with c++ and OOP programming, I've almost good knowledge of C language but all these new concepts are difficult to grasp and implement with data structure. I'm trying to make a good generic ADT following the STL style with iterator pattern and template.
There are no Syntax error, instead, there is a big logic problem with element insertion(pushFront function) that insert only the last element(check main function), I tried to debug but still can't find the problem. Hope that someone can help me :-)
These are my code snippet
Node class:
//Forward declaration
template<class T>
class LinkedList;
//Node should be structure?
template<class T>
class Node
{
friend class LinkedList<T>;
public:
Node(): pPrev_(nullptr), pNext_(nullptr) {}
Node(const T& value): data_(value), pPrev_(nullptr), pNext_(nullptr) {}
/*
* Implementing double linked list node
* data_: node's data of type T
* pNext_: pointer to the next node
* pPrev_: pointer to the previous node
*/
// if I put Private there some errors with private stuff, I have declared also LInkedList as friend
T data_;
Node<T>* pPrev_;
Node<T>* pNext_;
};
Iterator Class:
template<class T>
class ListIterator
{
// Declaring LinkedList friend class, now
//LinkedList can access to all data in this class
friend class LinkedList<T>;
public:
//Constructors
ListIterator();
ListIterator(Node<T>* node);
//Destructor
~ListIterator();
// Assignement Overload
//ListIterator<T> operator=(const)
//Deferencing Overload
T operator*();
//Prefix Overload
ListIterator<T> operator++();
ListIterator<T> operator--();
//Postfix Overload
ListIterator<T> operator++(int);
ListIterator<T> operator--(int);
//Relational Overload
bool operator==(const ListIterator<T>& Node);
bool operator!=( const ListIterator<T>& Node);
private:
// Actual node holden by iterator
Node<T>* curNode_;
};
/*
LIST_ITERATOR IMPLEMETATION
*/
template <class T>
ListIterator<T>::ListIterator(): curNode_(nullptr){}
template <class T>
ListIterator<T>::ListIterator(Node<T>* node): curNode_(node) {}
//Destructor
template <class T>
ListIterator<T>::~ListIterator() {}
//Deferencing Overload
template <class T>
T ListIterator<T>::operator *()
{
//Return the VALUE of the current node holden by iterator
return this->curNode_->data_;
}
//Prefix Overload
template <class T>
ListIterator<T> ListIterator<T>::operator ++()
{
/*
* Check if the next node is a valid node, then
* the current node will be the next node
* Return the value of the current node
*/
if (this->curNode_->pNext_ != nullptr)
this->curNode_ =this->curNode_->pNext_; //Like it++, jump to the next node
return *this;
}
template <class T>
ListIterator<T> ListIterator<T>::operator --()
{
/*
* Check if the previous node is a valid node, then
* the current node will be the previous node
* Return the value of the current node
*/
if( this->curNode_->pPrev_ != nullptr)
this->curNode_ = this->curNode_->pPrev;
return *this; //?? why return this
}
//Postfix Overload
template <class T>
ListIterator<T> ListIterator<T>::operator ++(int)
{
ListIterator<T> temp= *this;
++(*this);
return temp;
}
template <class T>
ListIterator<T> ListIterator<T>::operator --(int)
{
ListIterator<T> temp= *this;
--(*this);
return temp;
}
// Inequalities Overload
template <class T>
bool ListIterator<T>::operator==(const ListIterator<T>& node)
{
/*
* Check if the address of the current node is equal to the address of node param
*/
return( this->curNode_== node.curNode_);
}
template <class T>
bool ListIterator<T>::operator!=(const ListIterator<T>& node)
{
return !((*this) == node);
}
LinkedList Class:
template<class T>
class LinkedList
{
public:
typedef ListIterator<T> iterator;
//Constructors
LinkedList();
LinkedList(const LinkedList<T>& copyList);
//Destructor
~LinkedList();
//List Status Methods
bool isEmpty();
unsigned int getSize();
iterator begin();
iterator end();
//Should parameters be constant and passed by reference &? let's check with tester if there are some troubles
//Insert Methods
void pushFront(const T value);
void pushBack(const T value);
void insertAt(const T value,iterator& atPos);
//Remove Methods
void popFront();
void popBack();
void removeAt(iterator& pos);
void clear();
/** Addtional methods
*
* sort
* min,max,
* clear,
* overload <<
* print
*/
private:
/*
* Keeping a pointer to head and tail of the list;
* Size_: number of list's element
*/
Node<T>* Head_;
Node<T>* Tail_;
unsigned int Size_;
};
// LIST IMPLEMENTATION
// Constructors
template < class T>
LinkedList<T>::LinkedList()
{
/*
* Create a new empty node, head and tail are/share the same node at this step.
* Assign to head's pointer to next node NULL
* Assign to tail's pointer to previous node NULL
*/
this->Head_=this->Tail_= new Node<T>;
this->Head_->pNext_= nullptr;
this->Tail_->pPrev_= nullptr;
this->Size_=0;
}
// WIP TO CHECK
template <class T>
LinkedList<T>::LinkedList(const LinkedList<T>& list){
this->Head_=this->Tail_= new Node<T>;
this->Head_->pNext_= nullptr;
this->Tail_->pPrev_= nullptr;
this->Size_=0;
// create iterator to loop inside the container
for(iterator it= list.begin ; it != list.end(); it++)
this->pushBack(*it);
}
//Destructor
template <class T>
LinkedList<T>::~LinkedList()
{
this->clear(); //delete all nodes
delete this->Tail_;
}
//Begin & end()
template <class T>
ListIterator<T> LinkedList<T>::begin()
{
iterator it= this->Head_;
return it;
}
template <class T>
ListIterator<T> LinkedList<T>::end()
{
iterator it= this->Tail_;
return it;
}
//Clear
template< class T>
void LinkedList<T>::clear()
{
iterator it= this->begin();
while(it != this->end())
this->removeAt(it);
}
These are the methods that gives me error:
//Insert At
template <class T>
void LinkedList<T>::insertAt(const T value, iterator& atPos)
{
Node<T>* newNode= new Node<T>;
newNode->data_= value;
//Add links
if( atPos == this->begin())
{
newNode->pNext_=this->Head_;
this->Head_=newNode;
}
else if ( atPos == this->end())
//Still to implement
this->Tail_= newNode;
else
{
newNode->pNext_ = atPos.curNode_;
atPos.curNode_->pPrev_ = newNode;
atPos.curNode_->pPrev_->pNext_ = newNode;
newNode->pPrev_=atPos.curNode_->pPrev_;
}
atPos.curNode_= newNode;
this->Size_++;
}
template <class T>
void LinkedList<T>::pushFront(const T value)
{
iterator it= this->begin();
this->insertAt(value, it);
}
And here some lines to test the ADT:
#include <iostream>
#include <stdlib.h>
#include <string>
#include "LinkedList.h"
using namespace std;
int main() {
Node<int> nd(4);
ListIterator<int> it;
LinkedList<int> lst;
for(int i=0; i < 25;i++)
lst.pushFront(i);
for(it=lst.begin(); it != lst.end();it++)
{
cout << *it << endl;
system("Pause");
}
cout << "iia";
system("Pause");
return 0;
}
There are no errors in your output:
24
Press any key to continue . . .
23
Press any key to continue . . .
22
Press any key to continue . . .
...
Press any key to continue . . .
0
Press any key to continue . . .
iiaPress any key to continue . . .
P.S. don't use this where you can avoid it. Code will be easier for reading.

C++ circular dependency with intrusive linked list

I've implemented this intrusive linked list:
template <class Entry>
struct LinkedListNode {
Entry *next;
Entry *prev;
};
template <class Entry, LinkedListNode<Entry> Entry::*NodeMember>
class LinkedList {
public:
void init ();
bool isEmpty () const;
Entry * first () const;
Entry * last () const;
Entry * next (Entry *e) const;
Entry * prev (Entry *e) const;
void prepend (Entry *e);
void append (Entry *e);
void insertBefore (Entry *e, Entry *target);
void insertAfter (Entry *e, Entry *target);
void remove (Entry *e);
public:
Entry *m_first;
Entry *m_last;
};
...
template <class Entry, LinkedListNode<Entry> Entry::*NodeMember>
inline Entry * LinkedList<Entry, NodeMember>::next (Entry *e) const
{
return (e->*NodeMember).next;
}
...
It can be used like this:
struct MyEntry {
int value;
LinkedListNode<MyEntry> list_node;
};
LinkedList<MyEntry, &MyEntry::list_node> list;
list.init();
MyEntry entry1, entry2;
entry1.value = 3;
list.append(&entry1);
entry2.value = 5;
list.prepend(&entry2);
It works all right, until you need two objects which contain lists of one another:
struct MyEntry2;
struct MyEntry1 {
int value;
LinkedListNode<MyEntry1> node;
LinkedList<MyEntry2, &MyEntry2::node> list;
};
struct MyEntry2 {
int value;
LinkedListNode<MyEntry2> node;
LinkedList<MyEntry1, &MyEntry1::node> list;
};
Each MyEntry1 holds a list of MyEntry2's, and each MyEntry2 can only appear in the list of one MyEntry1; and the converse. However, this doesn't compile, because the member pointer &MyEntry2::node is taken before MyEntry2 is defined:
prog.cpp:33:27: error: incomplete type 'MyEntry2' used in nested name specifier
prog.cpp:33:41: error: template argument 2 is invalid
There isn't really any practical semantic to this problematic layout, it is only a theoretical problem I've found which may limit the usability of the generic linked list.
Is there any way around this which doesn't make the list considerably more impractical?
EDIT: the layout of all data structures here is completely defined. This is because the data members of LinkedList do not depend on the problematic NodeMember template parameter; only the functions do. The problem seems to be that the language is demanding that &MyEntry2::node be known even though it does not really need to be known at the time.
EDIT: it must be possible to use this generic list to add a structure into two or more lists; this is the purpose of the NodeMember template parameter - it specifies which LinkedListNode within the entry is to be used.
Here is an implementation using inheritance that does not suffer from
your problem.
template <typename Entry>
struct LinkedListNode {
Entry *next;
Entry *prev;
};
template <class Entry>
class LinkedList {
public:
void init ();
bool isEmpty () const;
Entry * first () const;
Entry * last () const;
Entry* next (Entry* e) const {
return e->next;
}
Entry * prev (Entry *e) const;
void prepend (Entry *e);
void append (Entry *e);
void insertBefore (Entry *e, Entry *target);
void insertAfter (Entry *e, Entry *target);
void remove (Entry *e);
public:
LinkedListNode<Entry> *m_first;
LinkedListNode<Entry> *m_last;
};
struct MyEntry2;
struct MyEntry1 : public LinkedListNode<MyEntry1> {
int value;
LinkedList<MyEntry2> list;
};
struct MyEntry2 : public LinkedListNode<MyEntry2> {
int value;
LinkedList<MyEntry1> list;
};
Here is a solution where the LinkedList has a functor as second
template argument. We use an accessor functor with a templated
operator() to remove code duplication and to delay look-up of the
name. Note: The accessor should actually be a member and treated with an
empty base optimization.
template <class Entry>
struct LinkedListNode {
Entry *next;
Entry *prev;
};
template <class Entry, typename Func>
class LinkedList {
public:
void init ();
bool isEmpty () const;
Entry * first () const;
Entry * last () const;
Entry * next (Entry *e) const {
Func f;
return f(e).next();
}
Entry * prev (Entry *e) const;
void prepend (Entry *e);
void append (Entry *e);
void insertBefore (Entry *e, Entry *target);
void insertAfter (Entry *e, Entry *target);
void remove (Entry *e);
public:
Entry *m_first;
Entry *m_last;
};
struct MyEntry2;
struct node_m_access {
template <typename T>
LinkedListNode<T> operator()(T* t) const {
return t->node;
}
};
struct MyEntry1 {
int value;
LinkedListNode<MyEntry1> node;
LinkedList<MyEntry2, node_m_access> list;
};
struct MyEntry2 {
int value;
LinkedListNode<MyEntry2> node;
LinkedList<MyEntry1, node_m_access> list;
};
This problem is equivalent to trying to do:
struct MyEntry2;
struct MyEntry1 {
MyEntry2 a;
};
struct MyEntry2 {
MyEntry1 b;
};
In the above case, the compiler needs to know the size of the MyEntry2 struct when generating MyEntry1. In your case, the compiler needs to know the offset of node in MyEntry2 while generating MyEntry1.
I'm not experienced in template-foo but I would guess that instead of making Entry a class, you want to use a pointer to a class.
Here's a small modification of pmr's accessor solution to reduce the amount of boilerplate. The trick is to first provide an incomplete "struct" declaration of the accessors, instantiate the LinkedList's with these, and later complete the accessors by inheriting from a template accessor class.
template <class Entry>
struct LinkedListNode {
Entry *next;
Entry *prev;
};
template <class Entry, class Accessor>
class LinkedList {
public:
void init ();
bool isEmpty () const;
Entry * first () const;
Entry * last () const;
Entry * next (Entry *e) const {
return Accessor::access(e).next;
}
Entry * prev (Entry *e) const;
void prepend (Entry *e);
void append (Entry *e);
void insertBefore (Entry *e, Entry *target);
void insertAfter (Entry *e, Entry *target);
void remove (Entry *e);
public:
Entry *m_first;
Entry *m_last;
};
template <class Entry, LinkedListNode<Entry> Entry::*NodeMember>
struct LinkedListAccessor {
static LinkedListNode<Entry> & access (Entry *e)
{
return e->*NodeMember;
}
};
struct MyEntry2;
struct Accessor1;
struct Accessor2;
struct MyEntry1 {
int value;
LinkedListNode<MyEntry1> node;
LinkedList<MyEntry2, Accessor2> list;
};
struct MyEntry2 {
int value;
LinkedListNode<MyEntry2> node;
LinkedList<MyEntry1, Accessor1> list;
};
struct Accessor1 : LinkedListAccessor<MyEntry1, &MyEntry1::node> {};
struct Accessor2 : LinkedListAccessor<MyEntry2, &MyEntry2::node> {};
With this, a convenience class can even be made for when there is no problem with the circular dependency:
template <class Entry, LinkedListNode<Entry> Entry::*NodeMember>
class SimpleLinkedList
: public LinkedList<Entry, LinkedListAccessor<Entry, NodeMember> >
{};