I'm making a Linked list which is generic in nature and have some basic functionality. Then I'm trying to make another template class called "Set" which is inheriting from LinkedList. But when I try to access "head" which is a Node<>* defined in Linked List. It's giving an error. My files are:
LinkedList.h
template <typename T>
struct Node {
T data;
Node<T> *next;
};
template <typename T>
class LinkedList {
public:
Node<T>* head;
int size;
LinkedList();
LinkedList(const LinkedList<T> &lst);
~LinkedList();
Node<T>* getHead();
Node<T>* getTail();
};
template <typename T>
class Set:public LinkedList<T> {
public:
void insert(T item);
friend ostream&(ostream& out, const Set<T> set)
};
and an implementation of insert is:
template <typename T>
void Set<T>::insert(T item) {
Node<T>* temp = head;
bool present = false;
while (temp != NULL) {
if (temp->data == item) {
present = true;
}
temp = temp->next;
}
if (present == false) {
/*Node<T> *tail = getTail();
Node<T>* newTail = new Node<T>(item);
newTail->next = NULL;
tail->next = newTail;*/
}
}
It says:
error: "head" was not declared in this scope in line "Node<T>* temp = head"
This C++ oddity is due to two-phase lookup and the fact that head is a dependant name (as a member of a base class that depends on the "current" class's template arguments):
[C++11: 14.6.2/3]: In the definition of a class or class template, if a base class depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member. [..]
Bypass unqualified lookup by introducing this into the expression (per [C++11: 3.4.5]):
Node<T>* temp = this->head;
// ^^^^^^
There's a longer explanation on this previous Stack Overflow answer:
Why do I have to access template base class members through the this pointer?
Here's a minimal(ish) testcase:
#include <iostream>
template <typename T>
struct Base
{
int x = 42;
};
template <typename T>
struct Derived : Base<T>
{
void foo();
};
template <typename T>
void Derived<T>::foo()
{
std::cout << x << '\n';
}
int main()
{
Derived<void> d;
d.foo();
}
// main.cpp: In member function 'void Derived<T>::foo()':
// main.cpp:18:18: error: 'x' was not declared in this scope
// std::cout << x << '\n';
// ^
(live demo)
To fix, change foo thus:
template <typename T>
void Derived<T>::foo()
{
std::cout << this->x << '\n';
}
(live demo)
You're inheriting from a dependent base class so member access needs to be qualified with this:
Node<T>* temp = this->head;
For more information, see this thread.
Related
I have a class like this:
#include <iostream>
template <class T>
class LL
{
using size_t = unsigned int;
class Node
{
T m_data;
Node* m_next;
Node(const T& data) :m_data{ data }, m_next{ nullptr }{}
friend std::ostream& operator<<(std::ostream& out, const Node& node)
{
out << node.m_data;
return out;
}
friend std::ostream& operator<<(std::ostream& out, const LL& ll);
friend class LL;
};
Node* m_first{ nullptr };
size_t m_size{ 0 };
Node* newNode(const T& data)
{
return new Node{ data };
}
public:
void push(const T& data)
{
Node* temp = newNode(data);
temp->m_next = m_first;
m_first = temp;
++m_size;
}
Node* head()
{
return m_first;
}
size_t size() const
{
return m_size;
}
~LL()
{
if (m_first)
{
Node* trav = m_first->m_next;
Node* foll = m_first;
while (trav)
{
delete foll;
foll = trav;
trav = trav->m_next;
}
delete foll;
}
}
friend std::ostream& operator<<(std::ostream& out, const LL& ll)
{
Node* trav = ll.m_first;
while (trav)
{
out << *trav << ' ';
trav = trav->m_next;
}
return out;
}
};
I also have a function template somewhere else below this class in the same file that tries to access Node and looks like this with two compiler errors:
template <typename T>
int getSize(LL<T>::Node* node) //C2065: node is undeclared, C3861: node is not found
{
if (node)
{
return 1 + getSize(node->m_next);
}
return 0;
} //does not compile
After sometime I tried this, again with two compiler:
template <typename T>
int getSize(LL<T>::Node<T>* node) //C2065 like before, C7510: use of dependent template name must be prefixed with 'template'
{
if (node)
{
return 1 + getSize(node->m_next);
}
return 0;
} //does not compile
After sometime again, I tried the below which compiled fine.
template <typename T>
int getSize(typename LL<T>::template Node<T>* node)
{
if (node)
{
return 1 + getSize(node->m_next);
}
return 0;
}
Now, when I tried to call this function from my driver function, I got compiler errors again:
int main()
{
LL<int> ll;
std::cout << getSize(ll.head()); //E0304, C2672 and C2783
//E0304: no instance of the function template "getSize" matches the argument list
//C2672: no matching overload function found
//C2783: could not deduce template argument for 'T'
}
I tried everything that I possible could and couldn't sort this problem out. Could someone please explain me what is going on?
Note: All codes that I've mentioned here are in the same file.
getSize(ll.head()) fails because of non-deduced context; template parameter T can't be deduced automatically.
If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.
1) The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id:
The declaration should be
template <typename T>
int getSize(typename LL<T>::Node* node) // using class instead of typename works for OP (MSVC)
{
//some code
}
And since Node is not a template you don't need to use template keyword.
LIVE
See Where and why do I have to put the “template” and “typename” keywords? about why use the keyword typename and template.
I have the following code:
#include <iostream>
using namespace std;
template <class T>
class Iterator;
template <class T>
class List;
template <class T>
class List {
public:
struct Node;
Node* first;
friend class Iterator<T>;
List() :
first(NULL) { }
Iterator<T> begin() {
cout << first->data << endl;
return Iterator<T>(*this, first); // <--- problematic call
}
void insert(const T& data) {
Node newNode(data, NULL);
first = &newNode;
}
};
template <class T>
struct List<T>::Node {
private:
T data;
Node* next;
friend class List<T>;
friend class Iterator<T>;
Node(const T& data, Node* next) :
data(data), next(next) { }
};
template <class T>
class Iterator {
private:
const List<T>* list;
typename List<T>::Node* node;
friend class List<T>;
public:
Iterator(const List<T>& list, typename List<T>::Node* node) {
cout << node->data << endl;
}
};
int main() {
List<int> list;
list.insert(1);
list.begin();
return 0;
}
First I set the node data to "1" (int). Ater that I just pass it to the Iterator constructor, but it changes the value of node->data.
I printed node->data before and after the call:
1
2293232
I guess that 2293232 is an address of something, but I can't find the reason this happens.
When you write
void insert(const T& data) {
Node newNode(data, NULL);
first = &newNode;
}
Then:
You create an object on the stack
Point some (more) persistent pointer to its address
Destruct it as it goes out of scope
So you're left with garbage stuff.
I'm no expert in using templates but I'm not sure why I'm getting error: 'SLinked_List' is not a class template: friend class SLinked_List<T>; in the definition of class SNode. What is wrong with this piece of code?
Thank you,
Pranav
#include <iostream>
#include <string>
template <typename T>
class SNode{
friend class SLinked_List<T>;
private:
T data;
SNode<T>* next;
};
template <typename T>
class SLinked_List{
private:
SNode<T>* head;
public:
SLinked_List(){
head = nullptr;
}
bool empty() const { return head == nullptr; }
void insert_first (const T&);
};
template <typename T>
void SLinked_List<T> :: insert_first (const T& t){
SNode<T>* node = new SNode<T>;
node->data = t;
node->next = head;
head = node;
}
int main(){
SLinked_List<std::string> ls;
ls.insert_first("Hello");
return 0;
}
When you use template arguments to refer to a name you are saying that this type already exists as a template and I want to reference a specific specialization of that template. Inside SNode, SLinked_List hasn't been declared yet, so this can't be allowed because the compiler doesn't even know if it's a template yet.
It's clear you want to befriend the specialization taking a T, so you need to declare SLinked_List before SNode:
template <typename T>
class SLinked_List;
template <typename T>
class SNode{
friend class SLinked_List<T>;
private:
T data;
SNode<T>* next;
};
Now the compiler knows that SLinked_List is a template and can be referenced as such.
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 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
};