Have a simple error. Looked at a bunch of posts and checked the causes on my files, but couldn't seem to fix it. The functions being called from my BST.cpp file are throwing the error in the title ("identifier "buildTree" is undefined). The functions in question are 'buildTree' and 'performSearchBST'. The CPP file is included in main and the class templates are declared on all of the functions. Probably a simple error but was hoping someone could help point it out for me. Code listed below. As always thank you in advance for your assistance.
Main File:
//..
#include "BST.cpp"
#include "Node.h"
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
int main()
{
//...
ifstream filename("grocery_upc_database.csv");
BST<UPC> tree = buildTree(filename); //build binary search tree of UPC objects
string code;
cout << "Please enter a UPC code(! to quit): ";
cin >> code;
while (code != "!")
{
long entry = stol(code); //convert user inputted string to type long int
UPC key(entry);
performSearchBST(tree, key);
cout << "\nPlease enter a UPC code(! to quit): ";
cin >> code;
}
return 0;
}
BST.cpp
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <fstream>
#include "BST.h"
using namespace std;
template <class T>
BST<T>::BST()
{
root = NULL;
}
template <class T>
BST<T>::BST(long upcdata, string descrip)
{
root->data = upcdata;
root->descrip = descrip;
}
template <class T>
void BST<T>::buildTree(string inFile)
{
string upcholder;
string description;
string line;
ifstream file;
file.open("grocery_upc_database.csv");
while (getline(file, line))
{
stringstream ss(line);
getline(ss, upcholder, ',');
getline(ss, description, '\t');
Node<T> newNode;
newNode->data = stol(upcholder);
newNode->descrip == description;
insert(newNode);
}
}
template <class T>
void BST<T>::insert(Node<T> *newNode)
{
insert2(root, newNode);
}
template <class T>
void insert2(Node<T> *&root, Node<T> *newNode)
{
if (root->data = NULL)
{
root = newNode;
}
else if (newNode->data < root->data)
{
insert2(root->left, newNode);
}
else
{
insert(root->right, newNode);
}
}
template <class T>
long BST<T>::stol(string item)
{
long i = atol(item.c_str());
return i;
}
template <class T>
bool BST<T>::performSearchBST(BST<T> bst, UPC key)
{
return performSearchBST2(bst,key);
}
template <class T>
bool performSearchBST2(BST<T> bst, UPC key)
{
if (bst.root == NULL)
return false;
if (bst.root->data == key)
return true;
else if (root->data < key)
return performSearchBST2(root->right, key);
else
return performSearchBST2(root->left, key);
}
BST.h
#include <iostream>
#include <string>
#include "Node.h"
using namespace std;
template <class T>
class BST
{
Node<T> *root;
public:
BST();
BST(long key, string descrip);
bool find(T item);
bool performSearchBST(BST<T> bst, UPC key);
void buildTree(string inFile);
void insert(Node<T>* newNode);
long stol(string item);
};
You have a simple error here.
First and foremost, your compiler doesn't know what is buildTree(String).
You have a non-static member function whose name is BST<T>::buildTree(String).
Secondly, as said in the comments, you cannot use such a non-static member function without an object of that type, since it operates on a specific object.
You can get by either:
Using it as a member function, thus:
BST<UPC> tree{};
tree.buildTree(filename);
Or, transform the function into a static function that builds a tree, and it should look like:
static BST<T> buildTree(string inFile)
{
\* Create and build the tree inside
return the tree
*/
}
and then you can use it by:
BST<UPC> tree = BST<UPC>::buildTree(filename);
Which is the proper name of the function.
Also, when using templates, you need to declare and define the function within the same .hpp file see this question for more information.
Related
This problem occurs in my main.cpp:
using namespace std;
#include <iostream>
#include "BST.h"
#include "Packet.h"
int main()
{
BST test; // It occurs on this line!
Packet one(1, "testPacket", 1, 1);
system("Pause");
}
The error on that line says:
argument list for class template "BST" is missing
I don't know how to fix it. I just want to initialize the BST. How can I fix this error? I'm not very experienced with templates. Please help. My priority is fixing this glaring problem right now. Can I get help?
For reference purposes:
BST.h:
#ifndef BST_H
#define BST_H
using namespace std;
template <typename T>
class Node {
public:
Node() : rlink(nullptr), llink(nullptr) {}
~Node() {}
private:
T data;
Node *rlink, *llink;
};
template <typename T>
class BST {
public:
BST();
void insert(T data);
private:
Node * root;
};
#endif
BST.cpp
#include "BST.h"
template <typename T>
BST<T>::BST() : root(nullptr) {}
template <typename T>
void BST<T>::insert(T data) {
if (root != nullptr) {
}
else {
cout << "NPTR" << endl;
}
}
Packet.h
#ifndef PACKET_H
#define PACKET_H
#include <string>
using namespace std;
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;
};
#endif
There are 2 problems.
The first is that Node needs to know what type T is, so you need to tell it when you use Node like this:
template <typename T>
class BST {
public:
BST();
void insert(T data);
private:
Node<T> * root;
};
Secondly, BST needs to know what its own type T is when you try to use it, so you need to do it like this:
BST<int> test; // Or whatever you are searching for in your tree. Doesn't have to be an int
P.S. Just heading this off now, you're probably going to need to implement BST in the header file. Failure to do so might cause linker problems.
P.P.S. I've been reading your comments on the original post, and what you actually probably need this instead:
BST<Packet> test; // Since you are searching for packets.
I am trying to get this to return a string, but i am having trouble getting it working. The goal is to have a doubly-linked list that points to strings. I am not allowed to have it contain the string, it must point to it instead. Currently i am having trouble getting my program to use it. For example, it always seems to return what the command was, and its confusing me and hard to explain.
#ifndef DOUBLY_LINKED_LIST_H
#define DOUBLY_LINKED_LIST_H
#include <iostream>
#include <string>
//#include "Playlist.h"
using namespace std;
class DoublyLinkedList
{
public:
DoublyLinkedList();
~DoublyLinkedList();
bool empty();
void append(string& s);
void insertBefore(string& s);
void insertAfter(string& s);
void remove(string& s);
void begin();
void end();
bool next();
bool prev();
bool find(string& s);
const string& getData();
private:
class Node
{
public:
Node (string *data, Node *next, Node *prev)
{m_data = data; m_next = next; m_prev = prev;}
string *m_data;
Node * m_next;
Node * m_prev;
};
Node *m_head;
Node *m_tail;
Node *m_current;
};
#endif // DOUBLYLINKEDLIST_H_INCLUDED
.cpp file>>>>
const string& DoublyLinkedList::getData()
{
string *m_tmp;
m_tmp = m_current->m_data;
cout << m_current->m_data << endl;
//cout << "returning: " << m_current->m_data << endl;
// return m_current->m_data;
return *m_tmp;
}
void DoublyLinkedList::append(string &s)
{
if (!m_head)
{
m_head = new Node(&s, NULL, NULL);
m_tail = m_head;
m_current = m_head;
}
else
{
m_tail->m_next = new Node (&s, NULL, m_tail);
m_tail = m_tail->m_next;
m_current = m_tail;
}
}
Consider the following example:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
void store_value(vector<string*>& vec, string& str)
{
vec.push_back(&str);
}
void create_and_store_value(vector<string*>& vec)
{
string str("This string is temporary");
store_value(vec, str);
}
int main(int argc, char** argv)
{
vector<string*> pointers;
create_and_store_value(pointers);
cout << *pointers.back() << endl;
string myPersistingString("Yay");
store_value(pointers, myPersistingString);
cout << *pointers.back() << endl;
return 0;
}
This example contains two function, a function store_value which behaves similar to your append function (except, for the purposes of this example working on a std::vector) and a second function showing the possible danger of taking the address of a reference (this is one of the possible hazards that I believe Manu343726 and Mats Petersson are preluding too).
The reason this is dangerous is because the string declared inside create_and_store_value does not persist after the completion of the function. This means that we are left with a pointer to memory which is probably not what we expect. On the other hand, creating a string inside the main function is fine, since the string there persists until the end of the program.
For us to help you further, I would suggest editing your question to give us an example of how you are calling your function. I would suggest pasting a minimal striped down version of your code including an example of how you are calling append, something like:
#include <blah>
class DoubleLinkedList
{
DoubleLinkedList(void)
{
// Include these inline to make copying and pasting simpler.
}
~DoubleLinkedList(void)
{
...
}
append(...) { ... }
getData(...) { ... }
};
int main(int argc, char** argv)
{
DoubleLinkedList dll;
// Show us how you are using this list
return 0;
}
In the above, replace the comments and dots with the relevant code.
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 8 years ago.
So, from a .csv file i'm creating users, which is from the class User. I'm trying to create a linkedlist, that will contain all users, but i'm getting an error inserting them into the linkedlist wich, by the way is named "ListaLigada". I can't figure it out by myself.
so, this is what i'm getting:
Error 1 error LNK2019: unresolved external symbol "public: void
__thiscall ListaLigada::insert(class User)" (?insert#?$ListaLigada#VUser####QAEXVUser###Z) referenced in function
"void __cdecl genUserLList(class ListaLigada &)"
(?genUserLList##YAXAAV?$ListaLigada#VUser#####Z) C:\Users\Daniel\documents\visual
studio 2010\Projects\Radio Station\Radio Station\Auxf.obj Radio
Station
If you can identify what i'm doing wrong i'll be gratefull, it has been long 2 days by now.
Here's the code that is related:
ListaLigada.h
#pragma once
#ifndef ListaLigada_H
#define ListaLigada_H
#include <cstddef>
#include <cassert>
template<class T>
class ListaLigada
{
public:
ListaLigada();
ListaLigada(T elem);
~ListaLigada(void);
void insert(T elem);
void remElem(T elem);
void remElem(int id_elem);
void searchElem(int id_elem);
void searchElem(T elem);
void clear();
private:
struct Node{
T data;
Node *next;
Node *prev;
} *p;
size_t list_size;
};
#endif
ListaLigada.cpp
#include "ListaLigada.h"
template<class T>
ListaLigada<T>::ListaLigada()
{
list_size=0;
this->p=new Node;
this->p=NULL;
}
template<class T>
ListaLigada<T>::~ListaLigada(void)
{
clear();
}
template<class T>
ListaLigada<T>::ListaLigada(T elem)
{
node *q, *t;
if(p == NULL)
{
p=new Node;
p->data= elem;
p->next= Null;
list_size++;
}
else
{
q=p;
while(q->next!= NULL)
q= q->next;
t= new node;
t->data= elem;
t->next=Null;
t->prev=q;
q->next=t;
list_size++;
}
}
template <class T>
void ListaLigada<T>::insert(T elem)
{
node *q, *t;
if(p == NULL)
{
p=new Node;
p->data= elem;
p->next= NULL;
list_size++;
}
else
{
q=p;
while(q->next!= NULL)
q= q->next;
t= new node;
t->data= elem;
t->next=NULL;
t->prev=q;
q->next=t;
list_size++;
}
}
template <class T>
void ListaLigada<T>::remElem(T elem)
{
node *q, *t;
if(p== NULL)
{
system("cls");
cout<<"There's nothing to remove\n";
_getch();
}
else
{
q=p;
while(q->next != NULL){
//e se for o unico elemento?
if(list_size==1)
{
~ListaLigada();
//blahblah limpar ficheiros
break;
}
else
{
if(q->data.getId() == )
}
}
}
}
template <class T>
void ListaLigada<T>::remElem(int id_elem){}
template <class T>
void ListaLigada<T>::searchElem(int id_elem){}
template <class T>
void ListaLigada<T>::searchElem(T elem){}
// deletes all the list elements
template <class T>
void ListaLigada<T>::clear()
{
node *q;
if( p == NULL )
return;
while( p != NULL )
{
q = p->next;
delete p;
p = q;
listSize--;
}
//assert(listSize==0);
}
auxf.h
#ifndef AUX_H
#define AUX_H
//#include "includes.h"
#include "ListaLigada.h"
#include "Music.h"
#include "User.h"
#include "RadioStation.h"
#include <conio.h>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <list>
#define MIN_LEN 2
bool strMinLen(string str, int min_len);
void fillField(string &to_fill, const string &what_is);
void checkFiles();
void loadInfo(vector<int> &vec); //carrega ids maximos
void regUser();
void addMusic();
void updateRestoreTxt(const int &line);
void loadRestore();
void updateRestore();
//void genUserLList(list<User> &lista);
void genUserLList(ListaLigada<User>);
#endif
auxf.cpp
//i'll post only the funciont that is related
void genUserLList(ListaLigada<User> &lista){
ifstream ifs;
ifs.open("users.csv");
if(ifs){
int to_read;
to_read=getNUsers(); //nr of users to read
string user_line;
getline(ifs, user_line, ','); //linha cabecalho
for(int i=0; i<to_read; i++){
user_line.clear();
string name, password;
int age;
char gender;
unsigned int id=0;
getline(ifs, user_line);
stringstream sstream;
sstream<<user_line;
string tmp;
stringstream sstmp;
char delim= ',';
getline(sstream, tmp, delim);
sstmp<<tmp;
sstmp>>id;
sstmp.clear();
tmp.clear();
getline(sstream, name, ',');
getline(sstream, tmp, ',');
sstmp<<tmp;
sstmp>>age;
sstmp.clear();
tmp.clear();
getline(sstream, tmp, ',');
sstmp<<tmp;
sstmp>>gender;
sstmp.clear();
tmp.clear();
getline(sstream, password, ',');
User n_user(id, name, age, gender, password);
/*list<User>::iterator it;
it=lista.end();
*/
lista.insert(n_user);
}
}
else{
cout<<"Lista Ligada ta fdd\n";
_getch();
}
}
Thanks in advance. I don't know what to do anymore... I'm reading the users
When you use a templated class, you need the complete definition, and that includes all methods as well. Therefore you can't split a templated class into header and source file, everything has to be in the header file.
You cannot implement template class in other compilation unit then you want to use it.
You should do it all in header or include this implementation into your header to keep it more readable.
The reason is that code for specialized template class is generated when it is used. If you only want to use some well known specialization of template class you can use implementation separated from header and just force those specialization to be created.
Here is some more:
Why can templates only be implemented in the header file?
the interface of Stack.h
#include "stdafx.h"
//use linkedlist to implement the stack
//which is different from using the array to implement the stack
#ifndef STACK_H
#define STACK_H
using namespace std;
namespace stackNameSpace {
template<class T>
struct StackNode {
T value;
T min_value; //current local min value
StackNode* next;
};
typedef StackNode<class T>* StackNodePtr;
template<class T>
class Stack {
private:
StackNodePtr top;
public:
Stack();
Stack(const Stack& a_stack);
~Stack();
bool empty() const;
T pop();
void push(T the_value);
T getMin();
};
} //end of namespace
#endif
The implementation of the stack.h
#include "stdafx.h"
//use linkedlist to implement the stack
//which is different from using the array to implement the stack
#ifndef STACK_CPP
#define STACK_CPP
#include <iostream>
#include <cstdlib>
#include "Stack.h"
using namespace std;
namespace stackNameSpace {
template<class T>
Stack<T>::Stack() : top(NULL) //here should be Stack<T> instead of Stack
{}
template<class T>
Stack<T>::Stack(const Stack& a_stack) {
if (a_stack.top == NULL) {
return NULL;
}
else {
StackNodePtr currentOld = a_stack.top;
//construct the top of the new stack
StackNodePtr currentNew = new StackNode<class T>;//the struct
currentNew->value = currentOld->value;
currentNew->min_value = currentOld->min_value;
top = currentNew;
//contruct the rest node in the stack
currentOld = currentOld->next;
while (currentOld != NULL) {
currentNew->next = new StackNode<class T>;
currentNew = currentNew->next;
currentNew->value = currentOld->value;
currentNew->min_value = currentOld->min_value;
currentOld = currentOld->next;
}
currentOld->next = NULL;
}
}
template<class T>
Stack<T>::~Stack() {
T data;
while (!empty()) {
data = pop();
}
}
template<class T>
bool Stack<T>::empty() const {
return (top == NULL);
}
template<class T>
T Stack<T>::pop() {
if (empty()) {
cout << "Error: popping an empty stack.\n";
exit(1);
}
T result = top->value;
StackNodePtr temp = new StackNode<class T>;
temp = top;
top = top->next;
delete temp;
return result;
}
template<class T>
void push(T the_value) {
StackNodePtr temp = new StackNode<class T>;
temp->value = the_value;
temp->min_value = min(the_value, getMin());//This is Much better
//temp->min_value = top->min_value; //This is NOT secure, since top may be NULL
temp->next = top; //update the top node
top = temp;
}
template<class T>
T getMin() {
if (top == NULL)
return INT_MAX;
else {
return top->min_value;
}
}
} //end of namespace
#endif
The function using the Stack class
#include "stdafx.h"
#include <iostream>
#include "Stack.h" //this is not the <stack>, which is STL
//using namespace std; //NOTE: this must be wrong! because can not use multiple namespace at the same time
using namespace stackNameSpace;
using std::cout;
using std::endl;
int main() {
Stack<int> sWithMin;
sWithMin.push(5);
cout<< sWithMin.getMin() << endl;
sWithMin.push(4);
cout<< sWithMin.getMin() << endl;
sWithMin.push(5);
cout<< sWithMin.getMin() << endl;
sWithMin.push(3);
cout<< sWithMin.getMin() << endl;
sWithMin.push(6);
cout<< sWithMin.getMin() << endl;
return 0;
}
When I compile the project, I get an error in main() that "error C2079: 'stackNameSpace::StackNode::value' uses undefined class 'stackNameSpace::T'"
I can not figure out the reason why it has the error. Could anyone please help me?
namespace stackNameSpace {
template<class T>
struct StackNode {
T value;
T min_value; //current local min value
StackNode* next;
};
So StackNode is a template that depends on a type parameter T.
typedef StackNode<class T>* StackNodePtr;
This is not part of a template definition and class T refers to a class named T.
(Actually class T always refers to a class named T, except in the construct template <class T>, which could be replaced by template <typename T>. With a template definition with type parameter T that type must be referred to using plain T, not class T.)
As you haven't declared a class named T yet, the StackNodePtr definition implicitly declares an incomplete class type at surrounding namespace scope (i.e the incomplete class type is ::stackNameSpace::T).
template<class T>
class Stack {
private:
StackNodePtr top;
Now here StackNodePtr is not dependent on the template parameter T. Instead it is a pointer to a fixed type StackNode<::stackNameSpace::T> and top->value will be of incomplete type class T unrelated to the template parameter of Stack.
If you use a Stack<int> and instantiate anything using top->value within such a stack, you'll see the error you show.
BTW: another, unrelated issue is that definitions of templates (including member functions of class templates) must be visible at the point where a template is instantiated. Typically that means that you should not put template member definition into a cppfile which is compiled separately. Instead they should be in a header file that is included wherever the template is used.
While JoergB correctly pointed out the issue with the code that you posted, I would like to throw some light on what he was explaining in the last part of his answer.
When using templates in Visual studio I would make sure that the header and implementation of the class come under a single compilation unit. Try renaming Stack.cpp to Stack.inl and include it at the end of Stack.h
void push(T the_value);
T getMin();
};
} //end of namespace
#include "Stack.inl"
#endif
Be sure to exclude Stack.inl from build. Right click on it in the Solution Explorer > Properties > Exclude from build > Yes.
Hi im working on a program that uses an array of linked lists but im having trouble running it. I keep getting this error and I cannot find a way to fix it. Im only going to include parts of the code that way everything isnt too cluttered. The error message is saying that lines 112 in NodeADT.h, line 141 in MultiListADT.h and line 21 in main.cpp are the ones throwing the error. Ill highlight those lines to make it easier.
Main.cpp
#include <iostream>
#include "MultiListADT.h"
#include <fstream>
#include <string>
using namespace std;
void main(void)
{
MultiListADT<string,100> myList;
string item;
ifstream data;
string input;
int x=0;
data.open("input.txt");
while (!data.eof())
{
getline(data,input);
myList.AddToFront(input); //This is line 21
}
cout << myList << endl;
system("pause");
}
MultiListADT.h
#include <iostream>
#include <fstream>
#include "NodeADT.h"
#include <string>
using namespace std;
template <class TYPE,int threads>
class MultiListADT
{
public:
/** Constructor **/
MultiListADT();
/** Destructor **/
~MultiListADT();
/** Declare accessors (observers) **/
void ResetListForward(int=0);
void ResetListBackward(int=0);
bool IsEmpty(int=0);
int LengthIs(int=0);
bool Search(string, bool=true,int=0);
void GetNextItem(TYPE &,int i=0);
void GetPreviousItem(TYPE &,int=0);
int GetInfo(int=0);
friend ostream& operator << (ostream&, MultiListADT<TYPE, 100>&);
/** Declare mutators (transformers) **/
void MakeEmpty();
void AddToFront(TYPE);
void AddToRear(TYPE);
void InsertInOrder(TYPE);
void Delete(TYPE);
void Sort();
private:
NodeADT<TYPE,threads>* head[threads];
NodeADT<TYPE,threads>* tail[threads];
int length;
string indices[threads];
NodeADT<TYPE,threads>* currentNode[threads];
};
template <class TYPE,int threads>
MultiListADT<TYPE,threads>::MultiListADT()
{
head[threads] = new NodeADT<string,threads>();
tail[threads] = new NodeADT<string,threads>();
head[threads]->setNext(tail[threads]);
tail[threads]->setPrevious(head[threads]);
length = 0;
}
template <class TYPE,int threads>
void MultiListADT<TYPE,threads>::AddToFront(TYPE item)
{
head[0]->AddToFront(item); //This is line 141
length++;
}
NoteADT.h
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
const int null = 0;
template<class TYPE, int threads>
class MultiListADT;
template <class TYPE, int threads>
class NodeADT
{
public:
NodeADT();
NodeADT(TYPE);
~NodeADT();
TYPE getInfo();
NodeADT<TYPE, threads>* getPrevious(int=0);
NodeADT<TYPE, threads>* getNext(int=0);
void setNext(NodeADT<TYPE, threads>*,int=0);
void setPrevious(NodeADT<TYPE, threads>*,int=0);
bool Search(TYPE, bool=true,int=0);
void AddToFront(TYPE item);
void AddToRear(TYPE item);
void InsertInOrder(TYPE);
bool Delete(TYPE);
friend ostream& operator << (ostream&, MultiListADT<TYPE, threads>&);
private:
TYPE info;
NodeADT<TYPE, threads>* prev[threads];
NodeADT<TYPE, threads>* next[threads];
};
template <class TYPE,int threads>
NodeADT<TYPE,threads>::NodeADT()
{
prev[threads] = null;
next[threads] = null;
}
template <class TYPE,int threads>
NodeADT<TYPE,threads>::NodeADT(TYPE item)
{
info = item;
prev = null;
next = null;
}
template <class TYPE,int threads>
void NodeADT<TYPE,threads>::AddToFront(TYPE item)
{
NodeADT<TYPE,threads> *temp = new NodeADT<TYPE,threads>;
temp->info = item;
temp->prev[0] = this;
temp->next[0] = next[0];
next[0]->prev[0] = temp; //This is line 112
next[0] = temp;
}
What do YOU think the error means?
On line 112, where do the values for next, prev and temp come from and what are they set to when it crashes? Knowing the values, why do you think it crashed?
Also in one of your NodeADT constructors you assign null to the last element of the array. Or so it appears.
Question: What happens when you assign a value to the element numbered 100 in an array of 100 elements, when element counting starts at 0?
I think the answer, which Zan Lynx has implied, is that you are using threads as an index into your arrays in the constructor of MultiListADT. In AddToFront you use 0 as the index, but that element in the array has never been initialised.