This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 9 years ago.
I'm trying to create a template c++ Stack, and i'm having some issue with the linker.
I've tried to put all the classes into one cpp file, and it works just fine, but the problem begin once I separate them into different files
here's my classes
main class :
#include <iostream>
#include "stack.h"
using namespace std;
int main()
{
Stack<double>* st = new Stack<double>();
st->push(new Data<double>(10));
cout << st->pop()->getData();
return 0;
}
stack.h :
#ifndef STACK_H
#define STACK_H
#include "data.h"
template <class T>
class Stack
{
public:
Stack():_current(NULL){}
void push(Data<T>* const);
Data<T>* pop();
private:
Data<T>* _current;
};
#endif;
stack.cpp :
#include "stack.h"
template <class T>
Data<T>* Stack<T>::pop()
{
if(this->_current == NULL)
{
cout << "Empty stack." <<endl;
return NULL;
}
else
{
Data<T>* tmpPtr = this->_current;
this->_current = this->_current->getPrev();
return tmpPtr;
}
}
template <class T>
void Stack<T>::push(Data<T>* const data)
{
if(this->_current == NULL) // Empty stack;
{
_current = data;
_current->setPrv(NULL);
}
else
{
Data<T>* tmpPtr = this->_current;
this->_current = data;
this->_current->setPrv(tmpPtr);
}
}
data.h
#ifndef DATA_H
#define DATA_H
template <class T>
class Data
{
public:
Data(T data):_data(data){}
T getData() const { return this->_data; }
void setPrv(Data* const prev){ this->_prev = prev; }
Data* getPrev() const { return this->_prev; }
private:
Data<T>* _prev;
T _data;
};
#endif
Put all the definitions of the template class functions in the .h. They basically aren't allowed to be in separate files.
This occurs becauses templates are not like typical classes. The compiler will generate a class for you off of your template instantiation. Because of this, the compiler will need to know where to lookup the function definitions, so put them inside the .h where the class is defined.
Template functions are not compiled until they're specialized(used), and your stack.cpp doesn't produce any machine code. Move them to stack.h
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.
Following codes are part of a Red Black Tree program which has to take item as a char or int, so I decided to use a template class, however I don't know how to extend it through the complete program and the compiler sends me thousand errors:
The code has German names, so if it makes it easier to understand, I will translate some of them:
baum = tree
knote = node
links = left
rechts = right
rot = red
doppel = double
mittlere = middle
eltern = parent
einfuegen = insert
rs = rb = red black
Knote.hpp
#pragma once
template <class T>
class Knote {
public:
Knote(T data = 0);
bool rot;
T item;
Knote *links;
Knote *rechts;
Knote *eltern;
};
Knote.cpp
#include "Knote.hpp"
Knote<int>::Knote(int data)
{
this->item = data;
eltern = nullptr;
links = nullptr;
rechts = nullptr;
rot = true;
}
now how should I do it for the rest?
Baum.hpp
#pragma once
#include "Knote.hpp"
#include <vector>
class Baum
{
public:
Baum();
void einfuegen(int x);
void ausgabe_levelorder();
void ausgabe_inorder();
private:
Knote<int>* head;
void rs_einfuegen(Knote<int>* &knote, Knote<int>* &eltern, int x, bool sw);
int rot(Knote<int>* &knote);
void links_rotation(Knote<int> * &links_knote);
void rechts_rotation(Knote<int> * &links_knote);
void levelorder(Knote<int>* knote, std::vector<Knote<int>*> &knoteQueue, int niveau, std::vector<int> &niveauQueue);
void sort_levelorder(std::vector<Knote<int>*> &knoteQueue, std::vector<int> &niveauQueue);
void inorder(Knote<int>* knote);
};
Baum.cpp
#include "Baum.hpp"
#include <iostream>
using namespace std;
Baum::Baum()
{
...
}
// XXX
void Baum::einfuegen(int x)
{
...
}
// XXX
int Baum::rot(Knote<int>* &knote)
{
...
}
// XXX
void Baum::rs_einfuegen(Knote<int> *& knote, Knote<int> *&eltern, int x, bool sw)
{
...
}
// XXX
void Baum::links_rotation(Knote<int>* &links_knote)
{
...
}
// XXX
void Baum::rechts_rotation(Knote<int>* &rechts_knote)
{
...
}
// XXX
void Baum::ausgabe_levelorder()
{
...
}
// XXX
void Baum::levelorder(Knote<int>* knote, vector<Knote<int>*> &knoteQueue, int niveau, vector<int> &niveauQueue)
{
...
}
// XXX
void Baum::sort_levelorder(vector<Knote<int>*> &knoteQueue, vector<int> &niveauQueue)
{
...
}
// XXX
void Baum::ausgabe_inorder()
{
inorder(head->rechts);
cout << endl;
}
// XXX
void Baum::inorder(Knote<int>* knote)
{
if (knote != nullptr)
{
inorder(knote->links);
cout << knote->item << " ";
inorder(knote->rechts);
}
}
Don't need to use Knote<T> in the class. Just use Knote. Instead of
Knote<T> *links;
Knote<T> *rechts;
Knote<T> *eltern;
just use:
Knote *links;
Knote *rechts;
Knote *eltern;
When you use the class template, make sure you provide a template parameter.
Knote* head;
is not right. You need to use
Knote<int>* head;
or
Knote<char>* head;
You pick the type that is appropriate for Baum.
Move the implementation of Knote to the .h file from the .cpp file. See Why can templates only be implemented in the header file?.
For Knote.h, your template <typename T> line should be template <class T>
Also, in your constructor for Knote, you can't assign an int (data) to a T variable (item). For the constructor, you should have T data, instead of int data, since you don't know what type data needs to be (because it's a template).
Templated classes also don't have a cpp file. The implementation has to go in the .h after the class declaration (unless forward declared). If you do want to separate your header and "implementation" code parts, keep the .h as normal, but make an .hpp file for your method implementations. In the .h after the class declaration, put #include "Knote.hpp".
For normal methods, the format goes like the following:
template <typename T>
void Knote<T>::myMethod(parameters)
{
//normal method stuff
}
For friend methods that take the templated class as a parameter, such as an overloaded the insertion operator (<<), the format goes like this:
//in class declaration in .h
template <class T>
class Bob
{
//variables here
template <typename U>
void myfunc(Bob<U> value); //have to use a different template variable
}
//define as normal in the .hpp (or further down the file if no .hpp used)
To start off, I'm kind of new to instantiation files, headers, and source files.
I'm trying to get my code to compile, but I keep hitting a linker error where it says that I'm defining something twice.
I have 6 Files:
- Instantiation.cpp Lab5.cpp Students.cpp Queue.cpp Students.h Queue.h
Instantiation:
#include "Students.cpp"
#include "Lab5.cpp"
#include "Queue.cpp"
template class Queue<int>;
template class QueueNode<int>;
template class Queue < Students* >;
template class QueueNode < Students* >;
Lab5:
#include "Queue.h"
#include "Students.h"
#include <iostream>
using namespace std;
int main(){
Queue <Students*> studentQueue;
Queue <int> integerQueue;
return 0;
}
Students.cpp:
#include "Students.h"
Students::Students(){
}
void Students::printStudent(){
}
Queue.cpp:
#include "Queue.h"
template <class DataType>
Queue<DataType>::Queue(int i){
i = queueSize;
}
template <class DataType>
Queue<DataType>::~Queue(){
}
template <class DataType>
void Queue<DataType>::enQueue(const DataType){
}
template <class DataType>
DataType Queue<DataType>::deQueue(){
return 0;
}
template <class DataType>
DataType Queue<DataType>::topQueue() const {
return 0;
}
template <class DataType>
bool Queue<DataType>::isEmpty() const {
return true;
}
template <class DataType>
bool Queue<DataType>::isFull() const{
return true;
}
Students.h:
#ifndef STUDENTS_H
#define STUDENTS_H
class Students{
public:
char lastName[20];
char firstName[20];
int ID; // ID
Students(); // constr
void printStudent(); // print info
};
#endif
Queue.h:
#ifndef QUEUE_H
#define QUEUE_H
template <class DataType>
class QueueNode {
public:
DataType data;
QueueNode<DataType> *next;
};
template <class DataType>
class Queue {
private:
QueueNode<DataType> *front;
QueueNode<DataType> *back;
int queueSize; // size of a Queue
int queueCnt; // elem count in a Queue
public:
Queue(int = 10); // class constr. - initialize vars
~Queue(); // class destructor - remove all mem space used by queue elems
void enQueue(const DataType); // add item to back of queue
DataType deQueue(); // remove first item from queue and return its value
DataType topQueue() const; // return the value of the first item in the queue
bool isEmpty() const; // returns true if there are no elems in the queue
bool isFull() const; // returns true if no system mem for a new queue node
};
#endif
Here's the output:
http://i.imgur.com/cAPdtKG.png
Please, help.
I don't really get why it thinks I'm defining anything twice.
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 8 years ago.
There is a problem with this code and I can't understand it.
It seems the problem happens within the linking phase as I've googled, but in my case I think there is something wrong with my code, not in toolchains, but I just couldn't solve it after hours and hours of trying. I'd be happy if you help me correcting it.
I'm using Code::Blocks, and the latest version of MinGW.
main.cpp
#include <iostream>
#include <string>
#include "threadsafequeue.hpp"
using namespace std;
int main(){
threadsafe_queue<string> Q;
threadsafe_queue<string> X;
X.empty();
try{
string s;
}catch(empty_queue ex){
cout << ex.what() << endl;
}
return 0;
}
threadsafe_queue.cpp
#include "threadsafe_queue.hpp"
template <typename T>
threadsafe_queue<T>::threadsafe_queue(const threadsafe_queue& other){
std::lock_guard<std::mutex> lock(other.m);
threadsafe_queue<T>::data = other.data;
}
template <typename T>
void threadsafe_queue<T>::push(T new_value){
std::lock_guard<std::mutex> lock(threadsafe_queue<T>::m);
threadsafe_queue::data.push(new_value);
}
template <typename T>
std::shared_ptr<T> threadsafe_queue<T>::pop(){
std::lock_guard<std::mutex> lock(threadsafe_queue<T>::m);
if(data.empty()) throw empty_queue();
std::shared_ptr<T> const res(std::make_shared<T>(threadsafe_queue<T>::data.front()));
threadsafe_queue<T>::data.pop();
return res;
}
template <typename T>
void threadsafe_queue<T>::pop(T& value){
std::lock_guard<std::mutex> lock(threadsafe_queue::m);
if(data.empty()) throw empty_queue();
value = threadsafe_queue::data.front();
threadsafe_queue::data.pop();
}
template <typename T>
bool threadsafe_queue<T>::empty(){
std::lock_guard<std::mutex> lock(threadsafe_queue<T>::m);
return threadsafe_queue<T>::data.empty();
}
threadsafe_queue.hpp
#include <exception>
#include <memory>
#include <mutex>
#include <queue>
#ifndef THREADSAFE_QUEUE_HPP_INCLUDED
#define THREADSAFE_QUEUE_HPP_INCLUDED
struct empty_queue : std::exception
{
virtual const char * what() const throw()
{
return "The Queue is Empty.";
};
};
template <typename T>
class threadsafe_queue
{
private:
std::queue<T> data;
mutable std::mutex m;
public:
threadsafe_queue() {};
threadsafe_queue(const threadsafe_queue& other);
threadsafe_queue& operator= (const threadsafe_queue&) = delete;
void push(T new_value);
std::shared_ptr<T> pop();
void pop(T& value);
bool empty();
};
#endif // THREADSAFE_QUEUE_HPP_INCLUDED
And the error is :
...\ThreadSafeQueue\main.cpp|9|undefined reference to
`threadsafe_queue::empty()'|
Move everything from threadsafe_queue.cpp to threadsafe_queue.hpp.
Why can templates only be implemented in the header file?
Or, if you want declaration and implementation of template to be separated, rename threadsafe_queue.cpp to threadsafe_queue.tpp (not really needed, just for better clarity) and include it at the end of threadsafe_queue.hpp file.
You must include in your main.cpp also your implementation file:
threadsafe_queue.cpp
actually your template definitons must be in your threadsafe_queue.hpp file otherwise templates will not be instantiated.
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.