Passing template parameters to nested structs - c++

I'm trying to add a nested struct (Node) that takes the same template param 'T' passed into the baseclass (LinkedList).
When I try to template the outer LinkedList class, I get a "explicit specialization of non-template class LinkedList" error. If I don't add it, the private Nodes "head" and "tail" don't recognize 'T'
When I add the template to the Node class, I get a "Declaration of 'T' shadows template parameter" error. However, if I don't add it explicitly to the Node class, the 'T' is not recognized at all in the struct.
How do I declare template and pass it correctly from the LinkedList class to the nested, private Node struct correctly?
template<class T>
class LinkedList<T> {
private:
template<typename T>
struct Node {
T value;
Node<T>* next;
Node<T>* previous;
Node<T>(T value, Node<T>* next, Node<T>* previous)
:value(value),
next(next),
previous(previous){}
Node<T>& operator=(const Node<T>&) = delete;
};
Node<T>* head;
Node<T>* tail;
LinkedList& operator=(const LinkedList&) = delete;
public:
LinkedList<T>()
:head(nullptr),
tail(nullptr){}
~LinkedList<T>();
LinkedList& insertTail(T value);
};

Lose all the extraneous <T> madness and simply used the outer template parameter. It is perfectly legal to do so:
template<class T>
class LinkedList
{
private:
struct Node {
T value;
Node* next;
Node* previous;
Node(T value, Node* next, Node* previous)
: value(value), next(next), previous(previous)
{}
Node& operator=(const Node&) = delete;
};
Node* head;
Node* tail;
LinkedList& operator=(const LinkedList&) = delete;
public:
LinkedList()
: head(nullptr)
, tail(nullptr)
{}
~LinkedList();
LinkedList& insertTail(T value);
};
Related: My crystal ball tells me you should read this before implementing the rest of the functions that are only declared here.
Best of luck.

When declaring a primary template (i.e., not a specialization), don't add <T> after the name:
template<class T>
class LinkedList {
Node shouldn't be a template; for any particular T, a LinkedList<T> should only have one type of Nodes - those that hold T:
struct Node {
T value;
Node* next;
// ...
};
Finally, the <T> is implied when you write the template's name in its definition, so you don't need to explicitly specify it:
LinkedList()
:head(nullptr),
tail(nullptr){}
~LinkedList();

Related

Class Template with Nested Class Declaration (C++)

Given that a class template called Queue with a nested class Node (not a class template):
template<typename T>
class Queue {
private:
struct Node {
Node (T value) : value(value), next(nullptr) {}
Node (T value, Node* next) : value(value), next(next) {}
T value;
Node* next;
};
Node* head;
size_t sz;
void cleanList();
public:
Queue();
Queue(const Queue& st);
Queue& operator=(const Queue& st);
~Queue();
size_t size() const noexcept;
bool isEmpty() const noexcept;
T& front();
const Tt& front() const;
void enqueue(const T& elem);
void dequeue();
};
I can do this:
template<typename T>
void Queue<T>::enqueue(const T& elem) {
Node* temp = new Node(elem);
}
It compiles, but why does declaring a Node not need more information? (like Queue::Node)
After reading Templates and nested classes/structures, all 3 of these also works and compiles:
template<typename T>
void Queue<T>::enqueue(const T& elem) {
typename LLQueue<Object>::Node* temp1 = new Node(elem);
LLQueue<Object>::Node* temp2;
LLQueue::Node* temp3;
}
Why do all versions work? Which is preferred when using a nested class in a class template?
It compiles, but why does declaring a Node not need more information?
This is how unqualified name lookup happens in a member function scope. First the compiler checks the scope of the function, doesn't find anything, and then moves on to the class scope. In the class scope it sees Node, so name lookup succeeds and you get the Node type that is a member of the class.
Why do all versions work?
C++ lets you be as explicit as you want to be. Any name can be fully qualified and that is what you are doing. With typename LLQueue<Object>::Node, the typename isn't needed, but it doesn't hurt anything. Its like doing struct foo{}; struct foo f; the struct isn't needed but it is allowed by the grammar. The second line with LLQueue<Object>::Node is just a less explicit way and also allowed since typename isn't actually required. LLQueue::Node works because in a class template class_name is injected into the class scope and it is class_name<template_params>.

Nested template class constructor

I the compiler can't find the definition of my constructor for the nested class.
My nested class Node is in the middle and the constructor is at the end.
Errors:
error C2244: 'CircularDoubleDirectedList::Node::Node' : unable
to match function definition to an existing declaration see
declaration of 'CircularDoubleDirectedList::Node::Node'
definition
'CircularDoubleDirectedList::Node::Node(const T &)'
existing declarations
'CircularDoubleDirectedList::Node::Node(const T &)'
Code:
#ifndef CIRCULARDOUBLEDIRECTEDLIST_H
#define CIRCULARDOUBLEDIRECTEDLIST_H
#include "ICircularDoubleDirectedList.h"
template <typename T> class CircularDoubleDirectedList;
template <typename T> class Node;
template <typename T>
class CircularDoubleDirectedList :
public ICircularDoubleDirectedList<T>{
public:
//Variabels
Node<T>* current;
int nrOfElements;
direction currentDirection;
//Functions
CircularDoubleDirectedList();
~CircularDoubleDirectedList();
void addAtCurrent(const T& element) override;
private:
template <typename T>
class Node
{
public:
T data;
Node<T>* forward;
Node<T>* backward;
Node(const T& element);// The constructor
};
};
template <typename T>
CircularDoubleDirectedList<T>::CircularDoubleDirectedList(){
this->nrOfElements = 0;
this->current = nullptr;
this->currentDirection = FORWARD;
}
template <typename T>
CircularDoubleDirectedList<T>::~CircularDoubleDirectedList(){
//TODO: Destroy all nodes
}
template <typename T>
void CircularDoubleDirectedList<T>::addAtCurrent(const T& element){
Node<T>* newNode = new Node<T>(element);
newNode->data = element;
if (this->nrOfElements == 0){
newNode->forward = newNode;
newNode->backward = newNode;
}
else{
//this->current->forward = newNode;
//this->current->forward->backward = newNode;
}
//this->current = newNode;
}
template <typename T>
CircularDoubleDirectedList<T>::Node<T>::Node(const T& element){
this->data = element;
}
#endif
First, the forward-declared template <typename T> class Node; is not the same as CircularDoubleDirectedList::Node - the former is a global class template, the latter is a nested class.
Second, you don't need to declare CircularDoubleDirectedList::Node as a template (and if you do, you have to use another template parameter name for it, not T). But as I understand, for this case you should just make it non-template, so:
template <typename T>
class CircularDoubleDirectedList :
public ICircularDoubleDirectedList<T>{
private:
class Node
{
public:
T data;
Node* forward;
Node* backward;
Node(const T& element);// The constructor
};
public:
Node* current;
//...
};
template <typename T>
CircularDoubleDirectedList<T>::Node::Node(const T& element){
this->data = element;
}
You have two class templates named Node, while in reality you want one non-template class named Node. You have forward-declared ::Node<T>, and you have the nested ::CircularDoubleDirectedList<T>::Node<U>.
If you really want it like that, you'll have to add another template keyword to the constructor definition:
template <typename T> //because CircularDoubleDirectedList is a template
template <typename U> //because Node is a template
CircularDoubleDirectedList<T>::Node<U>::Node(const T& element) : data(element)
{}
However, I can't see a single reason to have Node be a template. Inside CircularDoubleDirectedList<T>, do you want to use nodes with type other than T? If not, make Node a normal non-template class:
template <typename T>
class CircularDoubleDirectedList :
public ICircularDoubleDirectedList<T>{
public:
//Variabels
Node<T>* current;
int nrOfElements;
direction currentDirection;
//Functions
CircularDoubleDirectedList();
~CircularDoubleDirectedList();
void addAtCurrent(const T& element) override;
private:
class Node
{
public:
T data;
Node* forward;
Node* backward;
Node(const T& element);// The constructor
};
};
template <typename T>
CircularDoubleDirectedList<T>::Node::Node(const T& element) : data(element)
{}

'=' : cannot convert from 'CircularDoubleDirectedList<int>::Node *' to 'Node *'

I have Node* current where I store a pointer to what node that is current at "top" of the list. When I set a new node as current I get the error:
'=' : cannot convert from 'CircularDoubleDirectedList<int>::Node *' to 'Node *'
while compiling class template member function 'void CircularDoubleDirectedList<int>::addAtCurrent(const T &)' with [ T=int ]
It is the three rows with //Problem comment that generates those errors if take them away everything works fine.
#include "ICircularDoubleDirectedList.h"
template <typename T> class CircularDoubleDirectedList;
class Node;
template <typename T>
class CircularDoubleDirectedList :
public ICircularDoubleDirectedList<T>{
public:
//Variables
Node* current;
int nrOfElements;
direction currentDirection;
//Functions
CircularDoubleDirectedList();
~CircularDoubleDirectedList();
void addAtCurrent(const T& element) override;
private:
class Node
{
public:
T data;
Node* forward;
Node* backward;
Node(const T& element);
};
};
template <typename T>
void CircularDoubleDirectedList<T>::addAtCurrent(const T& element){
Node* newNode = new Node(element);
newNode->data = element;
if (this->nrOfElements == 0){
newNode->forward = newNode;
newNode->backward = newNode;
}
else{
this->current->forward = newNode; // Problem
this->current->forward->backward = newNode; // Problem
}
this->current = newNode; //Problem
}
When you forward declare Node as being outside of the class here:
template <typename T> class CircularDoubleDirectedList;
class Node;
That is declaring a type Node in the global namespace. It is ::Node. Then, within your class declaration, current takes on that type:
template <typename T>
class CircularDoubleDirectedList
: public ICircularDoubleDirectedList<T>
{
public:
Node* current; // this is a pointer to ::Node.
};
Then you provide a declaration of CircularDoubleDirectedList<T>::Node. This is not the same type as ::Node. It also gets looked up first by name resolution rules. So in here:
template <typename T>
void CircularDoubleDirectedList<T>::addAtCurrent(const T& element){
Node* newNode = new Node(element); // newNode is a pointer to
// CircularDoubleDirectedList<T>::Node
But current is a pointer to the still-incomplete type ::Node. Hence the error - you have inadvertently created two types named Node.
If you're going to forward-declare Node, you have to do it inside the class:
template <typename T>
class CircularDoubleDirectedList
: public ICircularDoubleDirectedList<T>
{
class Node; // NOW it's CircularDoubleDirectedList<T>::Node
};

The serie of constructors

I have written this Node class:
template<class T>
struct Node{
Node() : content(), col(RED), parent(0), left(0), right(0) {}
Node(const Node& orig) : content(orig.content), col(orig.col), parent(orig.parent), left(orig.left), right(orig.right) {}
virtual ~Node() {}
Node<T>& operator= (const Node<T>& node);
template <class sT>
friend std::ostream& operator<<(std::ostream& out,const Node<sT>&node);
T content;
Color col;
Node<T> *parent,*left,*right;
};
Now i would create a Node object with within a Node with within a std::pair and I have written this:
Node<Node< pair<int,char> > > n1 (Node<pair<int,char> >( pair<int,char>(45,'a') ));
but the compiler shows me this error:
main.cpp:31:84: error: no matching function for call to ‘Node<std::pair<int, char> >::Node(std::pair<int, char>)’
Which is the exact syntax to get what I want?
You are missing a constructor: Node(const T& x);

class members restricted after converting to template

So I'm working with templates and I've run into a problem. After I converted my code into templates I am no longer able to access the private members of my classes. I get the error that 'current' is a private member of 'Iterator'. So first I have each class:
template <class T>
struct nodeType {
T info;
nodeType<T> *link;
};
template <class T>
class Iterator {
public:
Iterator();
Iterator(nodeType<T> *);
T operator*();
bool IsNull();
Iterator<T> operator++();
Iterator<T> operator++(int);
bool operator==(const Iterator<T> &) const;
bool operator!=(const Iterator<T> &) const;
Iterator<T> &operator=(T);
private:
nodeType<T> *current;
};
template <class T>
class LinkedList {
public:
LinkedList();
LinkedList(const LinkedList<T> &);
~LinkedList();
void InsertHead(T);
Iterator<T> InsertAfter(T, Iterator<T>);
Iterator<T> Search(T);
bool IsEmpty();
void Print();
void DestroyList();
Iterator<T> Start();
Iterator<T> End();
const LinkedList<T> &operator=(const LinkedList<T> &);
private:
nodeType<T> *head;
};
Before I used templates I used the following code, but not current is private and this no longer works.
template <class T>
Iterator<T> LinkedList<T>::InsertAfter(T input, Iterator<T> marker) {
Iterator<T> newNode = new nodeType<T>;
Iterator<T> findNode = marker;
newNode = input;
newNode.current->link = findNode.current->link;
findNode.current->link = newNode.current;
return findNode;
}
Then I tried to do the following and It get no errors but when I called the InsertAfter function to add a new item to the list it doesn't show up. I did a cout newNode = input; and it shows the value I want to insert, but the nodes don;t seem to connect up. Why can't I use the previous code I was doing before? Like newNode.current->link = findNode.current->link;
template <class T>
Iterator<T> Iterator<T>::operator++() {
current = current->link;
return *this;
}
template <class T>
Iterator<T> Iterator<T>::operator++(int) {
Iterator<T> temp;
temp = *this;
++(*this);
return temp;
}
template <class T>
Iterator<T> LinkedList<T>::InsertAfter(T input, Iterator<T> marker) {
Iterator<T> newNode = new nodeType<T>;
Iterator<T> findNode = marker;
newNode = input;
newNode++ = findNode++;
findNode++ = newNode;
return findNode;
}
You can't do newNode.current within a member function of LinkedList, because current is private to Iterator. That's what private means - it is only accessible from member functions of the class it belongs in.
Clearly your "old" code was different. Possibly you had Iterator friend LinkedList in the old code. If you post your old code it might clear things up.