I am trying to create a class linkedList using template but when I compile it the IDE gives an error :
undefined reference to `listType::add(int)
I am not understanding why ?
linkedList.h
#ifndef LINKEDLISTS_H_INCLUDED
#define LINKEDLISTS_H_INCLUDED
#include "struct.h"
template <class type1>
class listType
{
public:
void add(type1);
void print();
private:
node<type1> *head;
};
#endif // LINKEDLISTS_H_INCLUDED
LinkedList.cpp
#include "linkedLists.h"
#include "struct.h"
#include <iostream>
using namespace std;
template <class type1>
void listType<type1>::add(type1 temp)
{
node<type1> *t;
t->value=temp;
t->link=head;
head=t;
}
template <class type1>
void listType<type1>::print()
{
node<type1> *p;
p=head;
while(p!=NULL)
{
cout<<p->value<<endl;
p=p->link;
}
}
Struct.h
#ifndef STRUCT_H_INCLUDED
#define STRUCT_H_INCLUDED
template <class type1>
struct node
{
type1 value;
node *link;
};
#endif // STRUCT_H_INCLUDED
main.cpp
#include <iostream>
#include "linkedLists.h"
using namespace std;
int main()
{
listType <int> test;
test.add(5);
}
You can't have the implementation of templated classes and functions in the cpp file.
The code has to be in the header, so the including files can see the implementation, and instantiate the correct version with their template argument type.
Related
I am attempting to create a templated vector class, but upon compilation I am receiving an error of
def.hpp:3:1: error: 'TempVector' does not name a type
I keep referring to reference material and my syntax and handling of the header file declaration and definition (.h and .hpp) seem right to me, but I can not figure out what I am overlooking.
Below is the three files I am working with, thank you.
driver.cpp:
#include <iostream>
#include <string>
#include "dec.h"
using namespace std;
int main() {
TempVector <int> v1;
cout<<"ran successfully"<<endl;
}
dec.h:
#ifndef DEC_H
#define DEC_H
#include <iostream>
#include <utility>
// Declaration of class Vector
template <typename T>
class TempVector {
public:
TempVector ();
private:
T* array;
static const unsigned int spare = 10;
};
#include "def.hpp"
#endif
def.hpp:
template <typename T>
TempVector<T>::TempVector () {
std::cout<<"ran successfully";
}
I'm trying to implement a dynamic template queue in c++, but when I call the destructor I get a "double free or corruption (out)" error. Unfortunately I'm not allowed to change the file structure, or add any new methods/classes, or change the class/method declerations. I tried adding 5 items to a queue(rq1), before printing it out and destructing it, the print works fine, but I get an error when I destruct. Here is my code:
main.cpp
#include "resrcQueue.h"
#include <string>
#include <iostream>
using namespace std;
int main(){
queueNode<string>* q1 = new queueNode<string>("apples",100);
queueNode<string>* q2 = new queueNode<string>("lemons",200);
queueNode<string>* q3 = new queueNode<string>("gold",10);
queueNode<string>* q4 = new queueNode<string>("stone",11);
queueNode<string>* q5 = new queueNode<string>("brick",12);
resrcQueue<string> rq1;
rq1.enqueue(q1);
rq1.enqueue(q2);
rq1.enqueue(q3);
rq1.enqueue(q4);
rq1.enqueue(q5);
rq1.print();
delete &rq1;
return 0;
}
rsrcQueue.h
#ifndef RQUEUE
#define RQUEUE
#include <string>
#include <iostream>
#include "queueNode.h"
using namespace std;
template <class T>
class resrcQueue{
private:
queueNode<T>* head;
queueNode<T>* tail;
public:
resrcQueue();
~resrcQueue();
void enqueue(queueNode<T>* t);
void dequeue();
queueNode<T>* peek();
void print();
int tallyWeight();
string calculateStorageRequirements();
};
#include "resrcQueue.cpp"
#endif
resrcQueue.cpp
#include "resrcQueue.h"
#include <string>
#include <iostream>
using namespace std;
template <class T>
resrcQueue<T>::resrcQueue(){
head=NULL; tail=NULL;
}
template <class T>
resrcQueue<T>::~resrcQueue(){
queueNode<T>* currNode=head;
queueNode<T>*temp;
int count=1;
while(head){
cout<<count<<endl;
this->dequeue();
count++;
}
}
template <class T>
void resrcQueue<T>::enqueue(queueNode<T>* t){
queueNode<T>*newNode=NULL;
newNode = new queueNode<T>(t->getResrc(),t->getWeight());
if(head){//not empty
tail->next=newNode;
tail=newNode;
}else{//empty
head=newNode;
tail=newNode;
}
}
template <class T>
void resrcQueue<T>::dequeue(){
if(head){//not empty
queueNode<T>* temp=head;
head=head->next;
delete temp;
}else{//empty
cout<<"EMPTY"<<endl;
}
}
template <class T>
queueNode<T>* resrcQueue<T>::peek(){
return head;
}
template <class T>
void resrcQueue<T>::print(){
queueNode<T>* currNode=head;
while(currNode){
cout<<"Resource: "<<currNode->getResrc()<<endl;
cout<<"Quantity: "<<currNode->getWeight()<<endl;
currNode=currNode->next;
}
}
template <class T>
int resrcQueue<T>::tallyWeight(){
int totalWeight=-1;
if(head){
totalWeight=0;
queueNode<T>* currNode=head;
while(currNode){
totalWeight+=currNode->getWeight();
currNode=currNode->next;
}
}
return totalWeight;
}
template <class T>
string resrcQueue<T>::calculateStorageRequirements(){
int numNodes=0;
queueNode<T>* currNode=head;
while(currNode){
numNodes++;
currNode=currNode->next;
}
string r;
if(this->tallyWeight()<100){
r="wooden crate";
}else if(this->tallyWeight()>200 && numNodes>5){
r="steel crate";
}else if(numNodes>5){
r="silo";
}else{
r="LOGISTICS ERROR";
}
return r;
}
queueNode.h
#ifndef QNODE
#define QNODE
#include <string>
#include <iostream>
using namespace std;
template <class T>
class queueNode{
private:
T resrc;
int weight;
public:
queueNode* next;
queueNode(T r, int w);
~queueNode();
T getResrc();
int getWeight();
};
#include "queueNode.cpp"
#endif
queueNode.cpp
#include <string>
#include <iostream>
#include "queueNode.h"
using namespace std;
template <class T>
queueNode<T>::queueNode(T r, int w){
next=NULL;
resrc=r; weight=w;
//cout<<"Init with weight: "<<weight<<", and resource: "<<resrc<<endl;
}
template <class T>
queueNode<T>::~queueNode(){
cout<<"Resource Unit Destroyed"<<endl;
}
template <class T>
T queueNode<T>::getResrc(){
return resrc;
}
template <class T>
int queueNode<T>::getWeight(){
return weight;
}
makefile
main.out: main.cpp queueNode.h queueNode.cpp
g++ -static -g main.cpp -o main.out
run: main.out
./main.out
clean: main.out
rm main.out
Apologies if the question is a little specific and if I included too much code, I couldn't manage to duplicate the error which is why I posted the original code where I got the error, and I did struggle quite a lot of hours to fix it myself before posting it here, I will decrease the code length if it'll be better that way.
There's a reason we ask people to make a MCVE - in the process of doing this you'll probably find the answer to your question.
When you take your program and strip out ALL of the unnecessary code and consolidate it into one file that still exhibits the bug, you get something like this:
#include <string>
using namespace std;
template <class T>
class resrcQueue{ };
int main(){
resrcQueue<string> rq1;
delete &rq1;
}
This still exhibits the bug. The reason for this is you can't delete stack variables. Remove the delete statement.
#include <string>
using namespace std;
template <class T>
class resrcQueue{ };
int main(){
resrcQueue<string> rq1;
}
Here is the code for the question:
PlainInterface.h
/** PlainInterface.h */
#ifndef _PLAIN_INTERFACE
#define _PLAIN_INTERFACE
#include <vector>
template <class ItemType>
class PlainInterface{
public:
virtual int getSize () const = 0;
};
#endif
Plain.h
/** Plain.h */
#ifndef _PLAIN
#define _PLAIN
#include "PlainInterface.h";
template <class ItemType>
class Plain: public PlainInterface < ItemType > {
private:
std::vector<ItemType> a;
public:
Plain();
~Plain();
int getSize() const;
};
#include "Plain.cpp"
#endif
Plain.cpp
/* Plain.cpp */
#include <iostream>
#include "Plain.h"
//Constructors
template <class ItemType>
Plain<ItemType>::Plain() {
std::cout << "Created\n";
}
template <class ItemType>
Plain<ItemType>::~Plain() {
std::cout << "Destroyed\n";
}
template <class ItemType>
int Plain<ItemType>::getSize() const { return 0; }
So according to this question it said that you can either have all of the implementation in the header file, or put #include "Plain.cpp" at the end of the "Plain.h" file, or put the explicit instantiations at the end of the "Plain.cpp" file. I would like to keep the files seperate and not limit what is allowed into the templates. I tried the second option and it didn't work.
The errors that I am getting are that the constructor/deconstructor/getSize definitions in Plain.cpp are already defined. What am I doing wrong here?
You should remove #include "Plain.h" in your .cpp file, as you are creating a circular include otherwise.
Example:
//a.h
...
#include "b.cpp"
//b.cpp
#include "a.h"
a will include b, b will include a, and so on. This is probably why the second option you mentioned didn't work.
Here another answer that applies to your problem (I think): https://stackoverflow.com/a/3127374/2065501
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 7 years ago.
I have a templated class named DataHandler
#ifndef DATAHANDLER_H
#define DATAHANDLER_H
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <set>
#include "constants.h"
template <typename T>
using Car = std::pair< T, T>;
template <typename T>
using SparseMatrix = std::vector< Car<T> >;
template <class T>
class DataHandler
{
public:
// initializes a new DataHandler only if none has been created,
// otherwise return the living instance
static DataHandler<T>* getInstance()
{
if(!dataHandler)
dataHandler = new DataHandler();
return dataHandler;
}
void readFile();
SparseMatrix<T>* getSparseBlue(){ return &sparseBlue; }
SparseMatrix<T>* getSparseRed(){ return &sparseRed; }
virtual ~DataHandler();
private:
// static DataHandler to ensure only one instance can be created
static DataHandler<T> *dataHandler;
// private constructor to use DataHandler as a Singleton
DataHandler();
int numElem = 0;
int m_rows, m_cols = -1;
#endif // DATAHANDLER_H
The source file is:
#include "data_handler.h"
#include <fstream>
#include <algorithm>
#include <omp.h>
#include <chrono>
using namespace std;
using namespace constants;
// Global static pointer used to ensure a single instance of the class.
template<typename T>
DataHandler<T>* DataHandler<T>::dataHandler = NULL;
template<typename T>
DataHandler<T>::DataHandler()
{
//ctor
}
template<typename T>
DataHandler<T>::~DataHandler()
{
//dtor
}
template<typename T>
void DataHandler<T>::readFile()
{
// do some stuff
}
// Instantiation of relevant templates
template class DataHandler<unsigned char>;
template class DataHandler<unsigned short int>;
In the last two lines I instantiate the templates which I define in main.cpp:
#include <iostream>
#include <chrono>
#include <fstream>
#include <algorithm>
#include "data_handler.h"
#include "dense_traffic_handler.h"
#include "sparse_traffic_handler.h"
#include "constants.h"
using namespace std;
// Check the number of rows/cols to choose between char or short int for the sparse case
bool matrixIsSmall()
{
return true;
}
void integerCase()
{
typedef unsigned char T;
DataHandler<T> *dh = DataHandler<T>::getInstance();
dh->readFile();
DenseTrafficHandler dth(dh); // ****** ERROR HERE *****
}
void charCase()
{
typedef unsigned char T;
DataHandler<T> *dh = DataHandler<T>::getInstance();
dh->readFile();
DenseTrafficHandler dth(dh); // ****** ERROR HERE *****
SparseTrafficHandler<T> sth;
set<unsigned short int> step = dh->getstep();
int currentStep = 0;
set<unsigned short int>::const_iterator stepToSave = step.begin();
}
int main(int argc, char *argv[])
{
if(matrixIsSmall())
charCase();
else
integerCase();
return 0;
}
Compiler gives me an error: undefined reference to DenseTrafficHandler::DenseTrafficHandler<unsigned short>(DataHandler<unsigned short>*)
DenseTrafficHandler header is like that:
#ifndef TRAFFICHANDLER_H
#define TRAFFICHANDLER_H
#include "constants.h"
#include "data_handler.h"
class DenseTrafficHandler
{
public:
template<typename T>
DenseTrafficHandler(DataHandler<T> *dh);
virtual ~DenseTrafficHandler();
private:
int m_cols, m_rows;
char* data;
char ** dense = NULL;
};
#endif // TRAFFICHANDLER_H
DenseTrafficHandler source is:
#include "dense_traffic_handler.h"
using namespace std;
using namespace constants;
template <typename T>
DenseTrafficHandler::DenseTrafficHandler(DataHandler<T> *datah)
{
DataHandler<T> *dh = datah;
dense = dh->getDense();
m_rows = dh->getm_rows();
m_cols = dh->getm_cols();
}
DenseTrafficHandler::~DenseTrafficHandler()
{
//dtor
}
So I have two questions:
Why do I receive this error and how can I manage it?
Is there a way in DataHandler source to not specify
template <typename T>
DataHandler<T>::functionName() for every function? (I mean something like using namespace Datahandler<T>)
You receive this error because compiler did not generate the code for this template type. One of solutions is to tell the compiler to do this explicitly by template instantiation:
add to your DenseTrafficHandler.cpp:
template class DenseTrafficHandler<unsigned short>;
Yes, just implement it in the header file. Reading more about it here.
I'm trying to create a linked list class in Eclipse but I can't get it to compile properly.
Here is my .cc file (code snipet)
#include <iostream>
#include "list.h"
using namespace std;
template <class T>
bool List<T>::isEmpty()
{
return (firstNode == NULL);
}
and here is my list.h file (code snipet)
#ifndef __LIST_H__
#define __LIST_H__
template <typename T>
class List {
public:
bool isEmpty();
private:
struct node {
node *following;
node *previous;
T *contents;
};
node *firstNode;
};
#include "list.cc"
#endif /* __LIST_H__ */
I try "Building All" in eclipse but I get the following error:
make all
Building file: ../list.cc
Invoking: Cross G++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"list.d" -MT"list.d" -o "list.o" "../list.cc"
../list.cc:13: error: redefinition of 'bool List<T>::isEmpty()'
../list.cc:13: error: 'bool List<T>::isEmpty()' previously declared here
make: *** [list.o] Error 1
Help please...thanks. I'll be happy to provide any clarifications needed
EDIT: I was given the .h file so I know that it is correct. I also know that I am supposed to have a .cc file called list.cc (it is included at the end of the .h file)
You need to change the extension of the file with the implementation.
The compiler will process this file for compilation and will process it twice, since you're including it in the header.
Your file looks like this:
#include <iostream>
#include "list.h"
using namespace std;
template <class T>
bool List<T>::isEmpty()
{
return (firstNode == NULL);
}
which will become
#include <iostream>
#ifndef __DLIST_H__
#define __DLIST_H__
template <typename T>
class List {
public:
bool isEmpty();
private:
struct node {
node *following;
node *previous;
T *contents;
};
node *firstNode;
};
#include "dlist.cc"
#endif /* __DLIST_H__ */
using namespace std;
template <class T>
bool List<T>::isEmpty()
{
return (firstNode == NULL);
}
which will in turn become
#include <iostream>
#ifndef __DLIST_H__
#define __DLIST_H__
template <typename T>
class List {
public:
bool isEmpty();
private:
struct node {
node *following;
node *previous;
T *contents;
};
node *firstNode;
};
template <class T>
bool List<T>::isEmpty()
{
return (firstNode == NULL);
}
#endif /* __DLIST_H__ */
using namespace std;
template <class T>
bool List<T>::isEmpty()
{
return (firstNode == NULL);
}
So the function isEmpty() is defined twice.
Rename the file to dlist.impl.
Try putting the definition for List<T>::isEmpty() in the same file as the class is declared.
Given the unusual form of the header you've been supplied with, to test it you will need another source file. To start with the new source file (say test.cpp) can just #include "list.h", which will check for any syntax errors but will not yet instantiate your List template.
(Just compile test.cpp, not list.cc, since list.cc is indirectly included by test.cpp)