I have written a small code to practice data structures and the beautiful C++.
The code below works completely fine if make the variables in SNode to public and remove the friend class ... line. However, based on the textbook I'm reading, this should be working fine.
The errors I get are as follow:
line 11: error: ‘SLinkedList’ is not a class template
In instantiation of ‘class SNode’: line 10: error: template argument required for ‘class SLinkedList’
In instantiation of ‘void SLinkedList::addFront(const E&) [with E = int]’: line 9: error: ‘int SNode<int>::elem’ is private
Below is the code written in Clion:
#include <iostream>
using namespace std;
template <typename E>
class SNode {
private:
E elem; //line 9
SNode<E> * next; // line 10
friend class SLinkedList<E>; //Provide SLinkedList access to these private variables (line 11)
};
template <typename E>
class SLinkedList {
public:
SLinkedList();
~SLinkedList();
bool empty() const;
const E& front() const;
void addFront(const E& e);
void removeFront();
void printAll() const;
private:
SNode<E> * head;
};
template <typename E>
SLinkedList<E>::SLinkedList():head(NULL){};
template <typename E>
bool SLinkedList<E>::empty() const {
return (head==NULL);
}
template <typename E>
void SLinkedList<E>::addFront(const E &e) {
SNode<E> * node = new SNode<E>;
node->elem=e;
node->next=head;
head=node;
}
template <typename E>
void SLinkedList<E>::removeFront() {
SNode<E> * temp = head;
head = head->next;
delete temp;
}
template <typename E>
const E& SLinkedList<E>::front() const {
return head->elem;
}
template <typename E>
SLinkedList<E>::~SLinkedList() {
while (!empty()){
removeFront();
}
}
template <typename E>
void SLinkedList<E>::printAll() const {
SNode<E> * itr =head;
while (itr != NULL){
cout<<itr->elem<<" ";
itr = itr->next;
}
}
int main() {
cout << "Hello, World!" << endl;
SLinkedList<int> test ;
test.addFront(2);
test.addFront(3);
test.addFront(6);
test.addFront(8);
test.addFront(19);
test.printAll();
return 0;
}
friend class SLinkedList<E>;
This template is not declared yet. Your C++ code gets compiled in an orderly manner, from the beginning of your source file to the end. Until this template gets declared later on in this header file, the compiler has no clue what this is.
The solution is very simple: add a forward declaration to the beginning of the header file, because the SNode template declaration:
template <typename E> class SLinkedList;
template <typename E>
class SNode {
private:
E elem;
SNode<E> * next;
friend class SLinkedList<E>;
};
friend class SLinkedList<E>;
At this point SLinkedList is not defined yet as a template, hence giving the error. Give a forward declaration for SLinkedList, everything will be fine than.
Add this :-
template <typename E>
class SLinkedList;
Related
I'm trying to implement stack data structure using singly linked list.
This is the header file that has template class of Node and List
#pragma once
template <typename E>
class SNode {
E elem;
SNode<E>* next;
public:
friend class SLinkedList<E>;
};
template <typename E>
class SLinkedList {
private:
SNode<E>* head;
public:
SLinkedList();
~SLinkedList();
bool empty() const ();
const E& front() const;
void addFront(const E& e);
void removeFront();
};
template <typename E>
SLinkedList<E>::SLinkedList() : head(NULL) {}
template <typename E>
SLinkedList<E>::~SLinkedList() {
while(!empty()) removeFront();
}
template <typename E>
bool SLinkedList<E>::empty() const {
return head==NULL;
}
template <typename E>
const E& SLinkedList<E>::front() const {
return head->elem;
}
template <typename E>
void SLinkedList<E>::addFront(const E& e) {
SNode<E>* tmp = new SNode<E>;
tmp->elem = e;
tmp->next=head;
head=tmp;
}
template <typename E>
void SLinkedList<E>::removeFront() {
SNode<E>* old = head;
head=head->next;
delete old;
}
This is a simple main code
#include <iostream>
#include "SNode.h"
using namespace std;
int main() {
SNode<int> A(1);
SNode<int> B(2);
SLinkedList<int> L();
L.push(A);
L.push(B);
return 0;
}
When I compile this code the compiler says
SLinkedList is not a class template
I have no idea why it says that since I did put
template
You need to forward declare the SLinkedList templated class. like this:-
template <typename E>
class SLinkedList;
template <typename E>
class SNode {
E elem;
SNode<E>* next;
public:
friend class SLinkedList<E>;
};
...
There are other errors in you code. I hope you are able to resolve them by youself.
You have vexing parse with
SLinkedList<int> L();
Which declares a.. function L, taking no parameters, and returning SLinkedList<int>.
Use
SLinkedList<int> L;
or
SLinkedList<int> L{};
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.
This is a General Trees program, where I am trying to find the depth of the tree (depth of 2) and calculate the size of the directory. The two errors are declaration errors (towards the bottom of Tree.cpp) and can't seem to declare the function properly.
Tree.cpp
#include "Tree.h"
#include <iostream>
using namespace std;
template <typename E>
bool Tree<E>::Position::isRoot() const
{
if (u->parent == NULL)
return true;
else
return false;
}
template <typename E>
bool Tree<E>::Position::isExternal() const
{
return (u->child.empty());
}
template <typename E>
bool Tree<E>::Position::operator==(Tree<E>::Position p)
{
if (u == p.u)
return true;
else
return false;
}
template <typename E>
Tree<E>::Position::Position(TreeNode *v)
{
u = v;
}
template <typename E>
typename Tree<E>::Position Tree<E>::Position::parent()
{
return Tree<E>::Position(u->parent);
}
template <typename E>
typename Tree<E>::PositionList Tree<E>::Position::children()
{
return (u->child);
}
template <typename E>
E Tree<E>::Position::operator*()
{
return u->e;
}
template <typename E>
typename Tree<E>::Position Tree<E>::root()
{
return typename Tree<E>::Position(r);
}
template <typename E>
int Tree<E>::size() const
{
return this->n;
}
template <typename E>
bool Tree<E>::empty() const
{
return size() == 0;
}
template <typename E>
void Tree<E>::insert(E e, Tree<E>::Position p)
{
TreeNode *v = new TreeNode() ;
v->e = e;
if (empty())
v->parent = NULL;
else
v->parent = p.u;
if (!empty() )
{
p.u->child.insertBack(v);
}
else
{
v->parent = NULL;
r = v;
}
++n;
}
template <typename E>
NodeList<typename Tree<E>::Position> Tree<E>::Positions()
{
typename Tree<E>::PositionList list;
preorder(r, list);
return list;
}
template <typename E>
void Tree<E>::preorder(Tree<E>::Position p, Tree<E>::PositionList &pl)
{
pl.insertBack(p);
if (p.u->child.empty()==false)
for(typename Tree<E>::PositionList::Iterator ii = p.u->child.begin(); ii!= p.u->child.end(); ++ii)
preorder(*ii, pl);
}
template <typename E>
int Tree<E>::depth(Tree<E>::TreeNode& u, Tree<E>::Position& p) //ERROR: Out-of-line definition of 'depth' does not match any declaration in 'Tree<E>'
{
if (p.isRoot())
return 0;
else
return 1+depth(u, p.parent());
}
template <typename E>
int Tree<E>::directorySize(Tree<E>::TreeNode& u, Tree<E>::Position& p) //Out-of-line definition of 'directorySize' does not match any declaration in 'Tree<E>'
{
int s = size(p);
if (!p.isExternal())
{
PositionList ch = p.children();
for (typename Tree<E>::PositionList::Iterator q = ch.begin(); q != ch.end(); q++)
s += depth(u, *q);
cout << name(p) << ": " << s << endl;
}
return s;
}
Tree.h
#ifndef TREE_H
#define TREE_H
#include <cstdlib>
#include "NodeList.cpp"
template <typename E>
class Tree {
public:
class TreeNode;
public:
class Position // a node position
{
public:
E operator*(); // get element
Position parent();
NodeList<Position> children();
bool isRoot() const; // root node?
bool isExternal() const; // external node?
bool operator==(Position p);
int depth(const Tree& u, const Position& p); //DECLARED(ERROR) - DEPTH OF TWO FUNCTION
Position(typename Tree<E>::TreeNode *v);
Position(){}
typename Tree<E>::TreeNode *u;
friend class NodeList<Position>;
};
typedef NodeList<typename Tree<E>::Position> PositionList;
public:
class TreeNode
{
E e;
TreeNode *parent;
typename Tree<E>::PositionList child;
friend class Tree;
friend class Tree<E>::Position;
public:
TreeNode(){
parent = NULL;
}
TreeNode(E,Tree<E>::Position*, Tree<E>::PositionList*);
TreeNode& operator=(const TreeNode &t)
{
parent = t.parent;
child = t.child;
e = t.e;
}
};
public: // public functions of Tree
Tree<E>(){
n = 0;
}
int size() const; // number of nodes
bool empty() const; // is tree empty?
int directorySize(const TreeNode& u, const Position& p); //DECLARED(ERROR) - SIZE OF DIRECTORY
Position root();
PositionList Positions();
void insert(E e, Position p);
void preorder(Position p ,PositionList &pre_order);
private:
TreeNode *r;
int n;
friend class Position;
};
#endif
The error is only showing up in the Tree.cpp file.
There are multiple errors here:
The arguments are declared to be const qualified references but the const got dropped in the definitions.
depth() is a member of Tree<E>::Position not of Tree<E>.
The first parameter of depth() is a Tree<E> not a TreeNode.
Note that putting the code into a .cpp file is either confusion (if the intention is to include the file) or it will cause grief when using the template classes from another translation unit. This problem is unrelated to the question, though.
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 am learning C++ templates for the first time, and have copied this code from "Data Structures and Algorithms in C++ by Michael Goodrich."
I get the error "Line 13: SLinkedList is not a template." I am at a complete loss as to why it is not since I have used "template " everywhere.
// ------------------ DEFINITION FOR NODE ------------------------
template <typename E>
class SNode{
private:
E elem;
SNode<E>* next;
friend class SLinkedList<E>;
public:
SNode(E element = NULL);
const E getElem() const;
void setElem(E element);
};
template <typename E>
SNode<E>::SNode(E element){ elem = element;}
template <typename E>
const E SNode<E>::getElem() const
{return elem;}
template <typename E>
void SNode<E>::setElem(E element)
{elem = element;}
// -------------------- DEFINITION FOR SINGLY-LINKED LIST --------------
template <typename E>
class SLinkedList
{
private:
SNode<E>* head;
public:
SLinkedList();
~SLinkedList();
bool isempty() const;
const E& infront() const;
void addfront(const E& e);
void removefront();
};
template <typename E>
SLinkedList<E>::SLinkedList()
:head(NULL) {}
template <typename E>
SLinkedList<E>::~SLinkedList()
{while(!isempty()) removefront();}
template <typename E>
bool SLinkedList<E>::isempty() const
{return (head == NULL);}
template <typename E>
const E& SLinkedList<E>::infront() const {return head->elem;}
template <typename E>
void SLinkedList<E>::addfront(const E& element) {
SNode<E>* v = new SNode<E>;
v->elem = element;
v->next = head;
head = v;
}
template <typename E>
void SLinkedList<E>::removefront() {
SNode<E>* old = head;
head = old->next;
delete old;
}
int main()
{
std::cout<<"Checking SLinkedList ..."<<std::endl<<std::endl;
SLinkedList<int> intList;
intList.addfront(13);
std::cout<<intList.head->next->getElem();
return 0;
}
friend class SLinkedList<E>;
This can be anything. The compiler doesn't know what it is. But if you tell him before declaring SNode that it will be defined later...:
template <typename E>
class SLinkedList;
... it might work ;)
You are using SLinkedList<E> even before declaring it. Before using it in you class `SNode', please declare it which is known as forward declaration.