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>.
Related
According to Why isn't argument deduction allowed in function return type?
When specifying a return type in a template class member function we have to be specific, for example: "the type std::vector isn't a type, std::vector<int> is."
So why do both of these examples compile? If I don't include the <T> in the first example, it shouldn't even be considered a type right?
template<typename T>
Queue<T>::Queue(const Queue& st) {}
template<typename T>
Queue<T>::Queue(const Queue<T>& st) {}
Given this template class
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();
};
The reason these examples work is because of the injected class name. When you have
template<typename T>
some_type<T> some_type<T>::some_func(some_type)
the return type is not in scope of the class so you need to provide the template parameter. In the function parameter you are in the scope of the class and in the scope of the class some_type is injected as a name for some_type<T> so you don't need to use some_type<T>.
Thanks in Advance.
am using template class & i get an error saying "Error C2955 'List': use of class template requires template argument list"
This is my list Class
template <class T>
struct node{
T Data;
node<T> * prev;
node<T> * next;
};
template <class T>
class List
{
public:
node<T> * front;
node<T> * rear;
List();
virtual ~List();
bool isEmpty();
void insertFirst(T Data);
void insertBack(T Data);
void insertBefore(node<T> * before, T Data);
void insertAfter(node<T> * after, T Data);
int removeFirst();
int removeLast();
void removeBefore(node<T> * before);
void removeAfter(node<T> * after);
node<T> * find(T Data);
//void destroy();
void insertRangeBefore(node<T> * before, List<T> range);
void insertRangeAfter(node<T> * after, List<T> range);
void removeRange(node<T> * rangeFirst, node<T> * rangeLast);
template <class T>
List getSublist(node<T> * rangeFirst, node<T> * rangeLast);
};
I Want to Create an instance of list and then return the sublist
template<class T>
List<T> List<T>::getSublist(node<T>* rangeFirst, node<T>* rangeLast) {
return List();
}
template<class T>
List<T> List<T>::getSublist(node<T>* rangeFirst, node<T>* rangeLast)
// ^^^ corrections here
{
return List();
}
The unqualified name of the template (List) is equivalent to the fully qualified name (List<T>) only inside its definition (and those of its members). However, the return type here is neither, so must be fully qualified.
Edit Your header file does actually not declare this member function and your code will still not compile. You must provide a matching declaration, i.e.
template<class T>
class List
{
...
List getSublist(node<T>*, node<T>*); // not a template
};
Your code actually declared a templated member (with another type T as template parameter). Just remove the line template<class T> from the member declaration.
Btw, you may want to consider having node a nested type of List<T>. Then you can replace node<T> with node (almost) everywhere (except when you must qualify it, when it is List<T>::node or typename List<T>::node).
I'm new to std::shared_ptr and trying to use it in linked list implementation. The code is:
#pragma once
#include <memory>
template <typename T>
class Node
{
public:
Node();
Node(const T& anItem);
Node(const Node& anNode);
T getItem() const;
std::shared_ptr<Node<T>> getNext() const;
std::shared_ptr<Node<T>> getPrev() const;
void setItem(const T& anItem);
void setNext(std::shared_ptr<Node<T>> nextNodePtr);
void setPrev(std::shared_ptr<Node<T>> prevNodePtr);
private:
T item;
std::shared_ptr<Node<T>> next;
std::shared_ptr<Node<T>> prev;
};
template <typename T>
Node<T>::Node(): next(nullptr), prev(nullptr) {}
template <typename T>
Node<T>::Node(const T& anItem) : next(nullptr), prev(nullptr), item(anItem) {}
template <typename T>
Node<T>::Node(const Node& anNode) : next(anNode.getNext()), prev(anNode.getPrev()), item(anNode.getItem()) {}
template <typename T>
T Node<T>::getItem() const
{
return item;
}
template <typename T>
std::shared_ptr<Node<T>> Node<T>::getNext() const
{
return next;
}
template <typename T>
std::shared_ptr<Node<T>> Node<T>::getPrev() const
{
return prev;
}
template <typename T>
void Node<T>::setItem(const T& anItem)
{
item = anItem;
}
template <typename T>
void Node<T>::setNext(std::shared_ptr<Node<T>> nextNodePtr)
{
next = nextNodePtr;
}
template <typename T>
void Node<T>::setPrev(std::shared_ptr<Node<T>> prevNodePtr)
{
prev = prevNodePtr;
}
This is in a header file. In any of these member functions, dereferencing the shared pointer doesn't show up the members and methods.
For example, suppose that in setPrev() I typed the following:
prev->
Now if it's a raw pointer (I tested with raw pointer), intellisense will show the members and methods available. But for std::shared_ptr intellisense doesn't work, and the only thing I saw is the methods of std::shared_ptr itself (operator* for example). I'm wondering what I did wrong?
Additionally, if I type (*prev). VS2017 simply tells me:
IntelliSense: 'No members available'
BTW it works in main.cpp, just not working in the header file, which is painful as I have to check the header files frequently, so I'm wondering I did something wrong with the smart pointer.
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)
{}
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();