EDIT: Changed example code to code from my project that doesn't work.
I'm writing code in C++, learning templates and got stuck with some problem.
There's a class:
template<class T, class Cmp>
class AVLtree {
public:
AVLtree(const Cmp& _cmp) : root(nullptr), cmp(_cmp) {}
AVLtree(const AVLtree& ref);
~AVLtree();
AVLtree& operator = (const AVLtree& ref);
void Add(const T& key);
void TraverseDfs(void (*visit)(const T& key));
private:
struct Node {
Node* left;
Node* right;
T key;
int balance;
unsigned int height;
unsigned int inheritence;
Node(const T& _key) : left(nullptr), right(nullptr), key(_key), balance(0), height(1), inheritence(1) {}
};
Node* root;
Cmp cmp;
void deleteTree(Node* root);
void traverse(Node* node, void(*visit) (const T& key));
Node* addNode(Node* node, const T& key);
Node* removeNode(Node* p, T key);
int bfactor(Node* node);
unsigned int height(Node* node);
void fixheight(Node* node);
Node* rotateRight(Node* p);
Node* rotateLeft(Node* q);
Node* balance(Node* p);
Node* findmin(Node* p);
Node* removemin(Node* p);
};
I want to define method addNode(Node* node, const T& key) out of class and here's what I write:
template<class T, class Cmp>
AVLtree<T, Cmp>::Node* AVLtree<T, Cmp>::addNode(Node* node, const T& key) {
return new Node(key);
if (!node) {
return new Node(key);
}
if (cmp(key, node->key)) {
node->left = addNode(node->left, key);
}
else {
node->right = addNode(node->right, key);
}
}
Then I try to run program and get such errors and warnings:
warning C4346: 'Node': dependent name is not a type
message : prefix with 'typename' to indicate a type
error C2061: syntax error: identifier 'Node'
error C2143: syntax error: missing ';' before '{'
error C2447: '{': missing function header (old-style formal list?)
It seems that I'm doing something wrong because, if I define method addNode(Node* node, const T& key) inside class, it works fine:
template<class T, class Cmp>
class AVLtree {
public:
...
private:
...
Node* addNode(Node* node, const T& key) {
return new Node(key);
if (!node) {
return new Node(key);
}
if (cmp(key, node->key)) {
node->left = addNode(node->left, key);
}
else {
node->right = addNode(node->right, key);
}
}
};
Any guesses what might be wrong?
Thanks for answers. Got a solution:
Just added typename before method definition outside of class. It looks like this:
template<class T, class Cmp>
typename AVLtree<T, Cmp>::Node* AVLtree<T, Cmp>::addNode(Node* node, const T& key) {
...
}
It seems that this is some spicialization of Visual Studio because I can see that other compilers work fine with such code without any errors.
It seems that I'm doing something wrong
No. This is a famous "bug/feature" from oldish version of Microsoft's compiler.
Inside the body of C1<T>::Work definition, the name lookup for Node is supposed to find C1<T>::Node. See Name lookup on cppreference.com for more information:
Member function definition
For a name used inside a member function body, a default argument of a member function, exception specification of a member function, or a default member initializer, the scopes searched are the same as in class definition, except that the entire scope of the class is considered, not just the part prior to the declaration that uses the name. For nested classes the entire body of the enclosing class is searched.
Your code is accepted by other compilers, e.g. gcc:
template<class T>
class C1 {
public:
void CallWork() { Work(); }
private:
struct Node {
T x;
};
Node* Work();
};
template<class T>
C1<T>::Node* C1<T>::Work()
{
return new Node{1};
}
live demo
Related
How's it's structured .h:
template <typename T>
class Node {
template <typename> friend class BST;
public:
Node(T p) : data(p), rlink(nullptr), llink(nullptr) {}
~Node() {}
private:
T data; // The holder of PACKET.
Node *rlink, *llink;
};
template <typename T>
class BST {
public:
BST();
void insert(T &p);
void inorderTraversal() const;
private:
Node<T> * root;
};
This is the suspected function that I will be using and where the problem occurs:
void inorderTraversal() const{
stack <T> *iterStack;
Node <T> *currentNode = root;
iterStack->push(currentNode);
}
Error:
'void std::stack>>::push(const
Packet &)': cannot convert argument 1 from 'Node *' to 'Packet &&'
How can I fix this so that the stack can take in my nodes?
Note that Packet is an object that gets taken in by Node's private member T data.
Packet.h (for reference):
class Packet {
public:
Packet(int partId, string description, double price, int partCount) :
partId(partId), description(description), price(price), partCount(partCount) {}
int getPartId() const { return partId; }
string getDescription() const { return description; }
double getPrice() const { return price; }
int getPartCount() const { return partCount; }
private:
int partId;
string description;
double price;
int partCount;
};
Update:
Tried
template <typename T>
void BST<T>::inorderTraversal() const{
stack <Node<T> *> iterStack;
Node <T> *currentNode = root;
iterStack->push(currentNode);
}
Got errors:
'std::stack *,std::deque<_Ty,std::allocator<_Ty>>>' does not
have an overloaded member 'operator ->'
'std::stack *,std::deque<_Ty,std::allocator<_Ty>>>::push':
left operand has 'class' type, use '.'
When in doubt, substitute the template parameters in your head and consider the code that results. For example, if T is to be Packet for your purposes here, then this:
std::stack<T> *iterStack;
Node <T> *currentNode = root;
iterStack->push(currentNode);
would be synonymous with
std::stack<Packet> *iterStack;
Node <Packet> *currentNode = root;
iterStack->push(currentNode);
Obviously this code is cut down (only because obviously yours is), and one could sanely question whether iterStack needs to be dynamic in the first place; see the aside it highly likely does not).
Regardless, clearly a std::stack<Packet> cannot hold Node<Packet>* objects; but a std::stack< Node<Packet>* > can. I.e.
std::stack< Node<T> > *iterStack;
Node <T> *currentNode = root;
iterStack->push(currentNode);
Aside, it is likely your stack doesn't need to be itself-dynamic in the first place.
std::stack< Node<T>* > stk;
Node <T> *currentNode = root;
stk.push(currentNode);
I am trying to create a Doubly Linked List and respective node class and am having an issue trying to add the data types of head and tail to my IntDLList class. I'm not quite sure what I missed, but an error is occurring stating that both head and tail were not declared, and that my Node class does not take a type. Any help is appreciated!
Edit: This does not seem to be a duplicate question, I looked at the other answers and trying to resolve an invalid use of incomplete type did not solve the same issue as my name type error.
IntDLList
using namespace std;
template <class T>
class IntDLList {
public:
IntDLList() {
head=tail=0; // error: 'head' was not declared in this scope (& same for tail)
}
~IntDLList();
int isEmpty() {
return head==0; // error: 'head' was not declared in this scope
}
void addToDLLHead(const T&);
void addToDLLTail(const T&);
T deleteFromDLLHead();
T deleteFromDLLTail();
void deleteDLLNode(const T&);
bool isInList(const T&) const;
void showList();
private:
IntDLLNode<T> *head, *tail; //error: IntDLLNode does not name a type
};
IntDLLNode
using namespace std;
template<class T>
class IntDLLNode {
friend class IntDLList;
public:
IntDLLNode() {next = prev = 0;}
IntDLLNode(const T& el, IntDLLNode *n = 0, IntDLLNode *p = 0) {
info = el;
next = n;
prev = p;
}
protected:
T info;
IntDLLNode<T> *next,*prev;
private:
};
I have the following implementation for the node class:
template<class T> class binTree; // forward declaration
template<class T> class Node {
friend class binTree<T>; // class binTree is friend
public:
//default constructor
Node(const T& d = T(), Node<T> *l = NULL, Node<T> *r = NULL) : data(d),
left(l), right(r) {};
private:
T data;
Node<T> *left, *right;
};
I'm trying to define a new node a the root of my tree, but I keep getting compilation errors...
template<class T>
void binTree<T>::insert(Node<T>*& n, const T& d){
if(n == NULL)
root = Node<T>(d);
}
I'm confused by the const T& d = T() parameter.
I think you just need to declare the binTree class and its members before you try to define the member. The following code compiles for me:
#include <cstdlib>
template<class T> class binTree; // forward declaration
template<class T> class Node {
friend class binTree<T>; // class binTree is friend
public:
//default constructor
Node(const T& d = T(), Node<T> *l = NULL, Node<T> *r = NULL) : data(d),
left(l), right(r) {};
private:
T data;
Node<T> *left, *right;
};
template <class T> class binTree
{
public:
binTree() { }
void insert(Node<T>*& n, const T& d);
private:
Node<T> root;
};
template<class T>
void binTree<T>::insert(Node<T>*& n, const T& d){
if(n == NULL)
root = Node<T>(d);
}
int main(int argc, char **argv)
{
Node<int>* nt;
binTree<int> btree;
btree.insert(nt, 4);
}
Having said this, your concept of the data structure seems messed up. Why does the insert routine in binTree require a node argument?
I'm not quite sure why you have that default override for the d variable in your default constructor. In my implementation of a Node for my Tree class, I had no default assignment. I think the issue is T(). I would recommend not trying to do that default assignment in the params listing, but instead do it in the BMI List. So it would look kind of like "data(new T), left(NULL), right(NULL)"
Additionally I would say I'm not quite certain as to why you are using T(). If that doesn't work, please post the error code so that we can have a better understanding of what is going on.
I am getting a few errors that I don't know about and have spent entirely to much time pulling my hair out. Here is my Header:
#ifndef MYBSTREE_H
#define MYBSTREE_H
#include "abstractbstree.h"
#include "MyBSTreeFunc.h"
using namespace std;
template<typename T>
class TreeNode
{
public:
T m_data;
TreeNode* m_right;
TreeNode* m_left;
};
template<typename T>
class MyBSTree:public AbstractBSTree<T> //LINE 18
{
private:
TreeNode<T>* m_root;
public:
void MyBSTree();
int size() const;
bool isEmpty() const;
int height() const;
const T& findMax() const;
const T& findMin() const;
int contains(const T& x) const;
void clear();
void insert(const T& x);
void remove(const T& x);
void printPreOrder() const;
void printPostOrder() const;
void print() const;
};
#endif
And my implementation file:
Line 1-6
void MyBSTree()
{
m_root -> m_data = NULL;
m_root -> m_right = NULL;
m_root -> m_left = NULL;
}
Line 13-21
template<typename T>
bool MyBSTree<T>::isEmpty() const
{
if (m_root== NULL)
return true;
else
return false;
}
Line 28-35
template < typename T >
const T& MyBSTree<T>::findMax() const
{
TreeNode* p = m_root;
while(p -> m_right != NULL)
p = p -> m_right;
return p;
}
The error for line 3 in the implementation says 'm_root' was not declared in this scope. But it's cool with lines 4 and 5. I'm guessing because m_data isn't a pointer? I don't know.
Next, Line 14, and 21, and quite a few others say that it expected an initializer before the '<' token. I assume they are all the same issue so I only put a few here.
Finally, it says for line 18 in the header: "template struct MyBSTree redeclared as a different kind of symbol." It then says Line 1 of my implementation is a previous declaration of 'void MyBSTree". I am assuming those go together.
Thanks for all the help.
You need to fix your constructor declaration:
template < typename T >
classMyBSTree
{
... // some stuff
public:
MyBSTree(); // no return type
... // some stuff
};
You alse need to fix your constructor:
template < typename T >
MyBSTree::MyBSTree() // proper ctor definition
{
m_root -> m_data = T(); // use the initializer for that data type
m_root -> m_right = NULL;
m_root -> m_left = NULL;
}
Lines 1-6: You've define a standalone function in the .cpp named void MyBSTree(). This is not part of the class. It's also bad that you named the function the same as your class. It looks like you want this to be your constructor, in which case you need this (I won't include the template stuff, as it's not the issue):
// in .h
class MyBSTree {
public:
MyBSTree(); // No void
}
// in .cpp
// Uses MyBSTree namespace.
MyBSTree::MyBSTree() { /* initialize your pointers etc */ }
This seems to be your main issue, and may fix the other problems too.
The reason the compiler cannot find m_roots is because your function is not part of the class. You would fix this by putting your function into the class scope with operator :: (e.g. myBSTree::myBSTree(){};)
Template functions cannot be placed in separate files from their class, you need to define all of your template class and function in the same file. Move the implementation of your functions into your header file.
I'm trying to create a doubly linked list and I'm getting this error:
error C2440: '=' : cannot convert from 'ListNode<T> *' to 'ListNode<T> *'
and i really don't know why. Can someone can help me?
template <class T>
class ListNode
{
private:
//Données membres
T m_Value;
ListNode<T> *m_Next;
ListNode<T> *m_Prev;
public:
//Constructeur
ListNode()
{
m_Value = NULL;
m_Next = NULL;
m_Prev = NULL;
}
ListNode<T>(T _Value)
{
m_Value = _Value;
m_Next = NULL;
m_Prev = NULL;
}
//Accesseurs
T getValue() const
{ return m_Value; }
void setValue(T _Value)
{ m_Value = _Value; }
ListNode<T>* getNext() const
{ return m_Next; }
void setNext(ListNode *_NextNode)
{ m_Next = _NextNode; }
ListNode<T>* getPrev() const
{ return m_Prev; }
void setPrev(ListNode *_PrevNode)
{ m_Prev = _PrevNode; }
};
template <class T>
class List
{
private:
//Données membres
int m_Compte;
ListNode<T> *m_Current;
ListNode<T> *m_Head;
ListNode<T> *m_Last;
...
Here is the function who cause the error
template <class T>
void operator+=(T _newValue)
{
Where the error is
This line is the faulty one. I'm trying to create a new node and to affect the current node which is a pointer to a ListNode
m_Current = new ListNode<T>(_newValue);
if (!m_Head)
{
m_Head = m_Current;
}
else
{
m_Last->setNext(m_Current);
m_Current->setPrev(m_Last);
m_Last = m_Current;
}
++m_Compte;
return;
}
template <class T> // <------ 'T'
class List
{
...
template <class T> // <------- 'T' again ?
void operator+=(T _newValue);
};
Seems that, T for List shadows T for operator +=. You may use typename U for operator += and give a try.
Also, are you sure that, you want a new type for operator += ? Or do you intend to use the same type as List<T>.
On side note, typical syntax for operator += is:
List& operator += (const List ©)
{
...
return *this;
}
I can't tell, because the entire class definition to the closing brace isn't here, whether operator+= is inside or outside the class definition.
If it is inside and you are defining it as an inline, then get rid of the template right above operator+=. The entire class is covered by the template declaration at the very top.
If it is being defined outside the class, then you need List::operator+= .