This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Undefined reference error for template method
Hello I have this code that is giving me this error:
undefined reference to `MyStack::push(int)' main.cpp
Why??
MyStack.h:
#ifndef STACK_H
#define STACK_H
template <typename T>
class MyStack
{
private:
T *stack_array;
int count;
public:
void push(T x);
void pop(T x);
void xd(){}
};
#endif /* STACK_H */
MyStack.cpp:
#include "mystack.h"
template <typename T>
void MyStack<T>::push(T x)
{
T *temp;
temp = new T[count];
for(int i=0; i<count; i++)
temp[i] = stack_array[i];
count++;
delete stack_array;
stack_array = new T[count];
for(int i=0; i<count-1; i++)
stack_array[i] = temp[i];
stack_array[count-1] = x;
}
template <typename T>
void MyStack<T>::pop(T x)
{
}
main.cpp:
#include <iostream>
#include "mystack.h"
using namespace std;
int main(int argc, char *argv[])
{
MyStack<int> s;
s.push(1);
return 0;
}
The definition of the members of the class template must be in the same file, but you've defined them in a different file (MyStack.cpp).
The simple solution is that add the following line to your MyStack.h file at the end:
#include "MyStack.cpp" // at the end of the file
I know that is .cpp file, but that will solve your problem.
That is, your MyStack.h should look like this:
#ifndef STACK_H
#define STACK_H
template <typename T>
class MyStack
{
private:
T *stack_array;
int count;
public:
void push(T x);
void pop(T x);
void xd(){}
};
#include "MyStack.cpp" // at the end of the file
#endif /* STACK_H */
If you do so, then #include "mystack.h" is not needed in MyStack.cpp anymore. You can remove that.
See C++ FAQ-35.12
You have to place your template class declaration and implementation inside header file because compiler needs to know about template implementation when instantiating template while compiling. Try to put implementation of MyStack inside MyStack.h
You can find more detailed explanation here. Just move to the "Templates and multiple-file projects" at the bootom of the article.
Related
My question is that, I have a template class template<class T> AList as base, and I wanna get a derived class from the template, i.e. get class BList: public AList<mydefinedtype> without much modification.
alist.h
#ifndef alist_h
#define alist_h
template<class T> class AList
{
public:
AList(){
arr = new T[20];
numitems = 0;
};
void append(T value);
private:
T *arr;
int numitems;
};
#endif /* alist_h */
alist.cpp
#include "alist.h"
template<class T> void AList<T>::append(T value)
{
arr[numitems] = value;
++numitems;
return;
}
blist.h
#include "alist.cpp"
#include <string>
using namespace std;
typedef struct
{
string a, b;
int key;
} record;
class BList: public AList<record>{
public:
void test(void){
cout << "this is from BList" << endl;
}
};
blist.cpp
#include "blist.h"
main.cpp
#include <iostream>
#include "blist.cpp"
using namespace std;
int main(){
record testRecord[3];
testRecord[0] = {"Mark", "A", 1};
testRecord[1] = {"Anla", "B", 2};
testRecord[2] = {"Cindy", "C", 3};
BList blist = BList();
for(auto i: testRecord){
// blist.append(i); // will compile error
blist.test();
}
return 0;
}
It will fail as follows, I wonder how to compile or how to fix the bug.
error info
Undefined symbols for architecture x86_64:
"AList<record>::append(s)", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
Not sure where comes from the issue.
// Example program
#include <iostream>
#include <string>
struct record{
int a;
};
template<class T>
class AList{
public:
AList()=default;
void append(T value){}
};
template<class T>
class BList:public AList<T>{
public:
void test(void){}
};
int main()
{
BList<record> blist;
record recordarr[3] ;
// some initialization
for(auto i:recordarr){
blist.append(i);
blist.test();
}
}
The problem you have is that the AList() constructor, append(T) and test() are only declared but not defined. The above code should compile.
You should put your template classes entirely in header files. See this question and this C++ FAQ for details on why.
You should also never #include .cpp files. You should only ever #include header files.
Below I have your code after the required modifications to make it compile. I also removed your memory leak.
alist.h:
#ifndef alist_h
#define alist_h
template<class T> class AList {
public:
AList() {
arr = new T[20];
numitems = 0;
};
~AList() {
delete[] arr;
}
void append(T value) {
arr[numitems] = value;
++numitems;
}
private:
T *arr;
int numitems;
};
#endif /* alist_h */
blist.h:
#ifndef blist_h
#define blist_h
#include "alist.h"
#include <string>
using namespace std;
typedef struct {
string a, b;
int key;
} record;
class BList: public AList<record> {
public:
void test(void) {
cout << "this is from BList" << endl;
}
};
#endif /* blist_h */
main.cpp:
#include <iostream>
#include "blist.h"
using namespace std;
int main() {
record testRecord[3];
testRecord[0] = {"Mark", "A", 1};
testRecord[1] = {"Anla", "B", 2};
testRecord[2] = {"Cindy", "C", 3};
BList blist = BList();
for (auto i: testRecord) {
blist.append(i);
blist.test();
}
return 0;
}
Summary of changes
I made the following changes:
Moved body of AList::append into alist.h, and deleted alist.cpp
Added AList destructor to free the dynamically allocated memory allocated in AList::AList
In blist.h, included alist.h instead of alist.cpp
Deleted blist.cpp
In main.cpp, included blist.h instead of blist.cpp
I am in the process of constructing a StackArray. I already have a "Stack.h" implemented with a constructor. I was wondering what I would do in my "StackArray.h" file to use the Stack.h file. I was thinking to use inheritance but it was giving me a error.
My code is as follows:
Array.h
#include <iostream>
#include <assert.h>
using namespace std;
#ifndef _ARRAY_H
#define _ARRAY_H
template<class T>
class Array{
private:
T *a;
int length;
public:
// constructor
Array (int len){
length = len;
a = new T[length];
for (int i = 0; i < len; i++){
a[i]=0;
}
}
// destructor
~Array()
{delete[] a;}
// operator overload
T& operator [](int i){
assert (i>=0 && i < length);
return a[i];
}
//get the length of the array
int arraylength(){
return length;
}
};
#endif
ArrayStack.h
#ifndef _ARRAYSTACK_H_
#define _ARRAYSTACK_H_
#include "Array.h"
using namespace std;
template<class T>
class ArrayStack
{
protected:
Array<T> a;
int n;
public:
ArrayStack(int len);
virtual ~ArrayStack();
};
template<class T>
ArrayStack<T>::ArrayStack(int len){
// I don't know what to do here to implemented constructor from another class.
}
#endif
Any suggestion would be great, Thank you
Andy
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 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.