I just started using template.
I want to create a linked list class which stores the address of Type (could be an object). Here is the layout of my project:
linkedlist.h
node.h
node.cpp
linkedlist.cpp
main.cpp
Node.h
template <class Type> struct Node
{
public:
Node<Type>();
Node<Type>(Type* x = 0, Node* pNext = 0);
Type* data;
Node* next;
};
Node.cpp
#include "node.h"
template<class Type> Node<Type>::Node()
{
next = 0;
data = 0;
}
template<class Type> Node<Type>::Node(Type* item, Node* ptrNext)
{
next = ptrNext;
data = item;
}
linkedlist.h
#include "node.h"
template <class Type> class LinkedList
{
private:
Node<Type>* root;
public:
LinkedList<Type>();
~LinkedList<Type>();
void insert(Type*);
void remove(Type*);
};
linkedlist.cpp
#include "linkedlist.h"
template <class Type> LinkedList<Type>::LinkedList()
{
root = 0;
}
template <class Type> LinkedList<Type>::~LinkedList()
{
Node* p;
while(p = root)
{
root = p->next;
delete p;
}
}
// many more....
In main.cpp, I have the following:
int main()
{
int *ptrA, *ptrB;
int a = 100, b = 10;
ptrA = &a;
ptrB = &b;
LinkedList<int>myList;
myList.insert(ptrA);
return 0;
}
and compiler threw linker errors:
1>main.obj : error LNK2019: unresolved external symbol "public: __thiscall LinkedList<int>::~LinkedList<int>(void)" (??1?$LinkedList#H##QAE#XZ) referenced in function _main
1>main.obj : error LNK2019: unresolved external symbol "public: void __thiscall LinkedList<int>::insert(int *)" (?insert#?$LinkedList#H##QAEXPAH#Z) referenced in function _main
1>main.obj : error LNK2019: unresolved external symbol "public: __thiscall LinkedList<int>::LinkedList<int>(void)" (??0?$LinkedList#H##QAE#XZ) referenced in function _main
Attempted Solution:
I called LinkedListmyList() instead. This can resolve the linker error, but I will not be able to call any member function.
myList.insert(ptrA) will say "Error: Expression must have a class type" if I put ().
So clearly this is not working.
What's the problem? I think the whole implementation has problems....
Thanks for your time.
Move the stuff from linkedlist.cpp .. to linkedlist.h
As it's declaring a 'template for making code' the machine code doesn't actually exist until you give the compiler the type you want to use.
For example, as long as all the template code is visible to the compiler, as soon as you go: LinkedList<int>myList the compiler creates the solid real class that makes a linkedlist of ints. In your case, the compiler can't see the template code, so isn't able to generate the machine code.
in c++11 you can say 'extern template': http://en.wikipedia.org/wiki/C%2B%2B11#Extern_template
in the header file, then implement the 'int' version in your linkeList.cpp file .. and it'll be available in main.cpp when it tries to use it.
This gives the advantage of the compiler not having to generate the machine code in every .cpp file where the template is used and makes compiling faster.
It can be done in c++98 too .. but it's a bit more tricky and not 100% portable as I understand it .. easier to just generate the code everywhere. Here's a good blurb on it for gnu gcc: http://gcc.gnu.org/onlinedocs/gcc/Template-Instantiation.html
Related
This question already has answers here:
Why do I get "unresolved external symbol" errors when using templates? [duplicate]
(3 answers)
Closed 3 years ago.
So I'm new to C++ and Visual Studio and I'm trying to implement a hash table using templates. I have four files: main.cpp, HashNode.h, HashTable.h, and HashTable.cpp.
main calls the HashTable constructor with a paramenter (the definition is in HashNode.h, with the implementation in the cpp file), but this throws 2 unresolved external errors: one for the called constructor, and one for what I assume to be the default constructor.
However, main also calls the HashNode constructor with no problems. HashNode has its implementation and declaration all in the HashNode.h file, but moving HashTable's implementation to its .h file didn't clear the error. So I'm very confused lol.
I'm running Visual Studio 2019, fresh install, and using the default build button to build it. It does compile and run other things (like hello world), just not this.
I've also tried adding random garbage into HashTable.cpp to see if the compiler just didn't see that it existed, but that's not the case. It also throws a compilation error then.
HashTable.h:
#pragma once
#include "HashNode.h"
template <typename T>
class HashTable
{
public:
void AddItem(int key, T item);
T* GetItem(int key);
HashTable(int buckets);
~HashTable();
int print();
private:
HashNode<T>** elements;
int buckets;
};
HashTable.cpp:
#include "HashTable.h"
#include "HashNode.h"
#include <stdexcept>
template<typename T>
HashTable<T>::HashTable(int buckets)
{
elements = new HashNode<T> * [buckets];
for (int i = 0; i < buckets; i++)
{
elements[i] = nullptr;
}
HashTable::buckets = buckets;
}
... //other methods defined below
HashNode.h
#pragma once
template <typename V>
class HashNode
{
public:
HashNode(int key, const V value) : k(key), v(value), next(nullptr) {}
int getKey () const { return k; }
V getValue() const { return v; }
HashNode* getNext() const { return next; }
void setNext(HashNode* next) { HashNode::next = next; }
void appendToChain(HashNode* last)
{
HashNode* curr = this;
while (curr->getNext() != nullptr)
{
curr = curr->getNext();
}
curr.setNext(last);
}
private:
int k;
V v;
HashNode* next;
};
Main.cpp:
#include <iostream>
#include "HashTable.h"
#include "HashNode.h"
int main()
{
std::cout << "Hello World!\n";
HashNode<int> node(1,1); //works fine
std::cout << node.getValue() << std::endl; //prints fine
HashTable<int> table(5); //throws error on compilation
}
It's probably just something stupid or that I'm blind, but here's the errors:
Error LNK1120 2 unresolved externals HashTable D:\C++\HashTable\Debug\HashTable.exe 1
Error LNK2019 unresolved external symbol "public: __thiscall HashTable<int>::HashTable<int>(int)" (??0?$HashTable#H##QAE#H#Z) referenced in function _main HashTable D:\C++\HashTable\HashTable\Main.obj 1
Error LNK2019 unresolved external symbol "public: __thiscall HashTable<int>::~HashTable<int>(void)" (??1?$HashTable#H##QAE#XZ) referenced in function _main HashTable D:\C++\HashTable\HashTable\Main.obj 1
Also, please don't hesitate to give me pointers if my code's bad. I've never really programmed anything in C++ before so any help is welcome!
You need to move the template function definitions into the header file.
A longer answer can be found here.
This question might be similar to some others out there; however, my question here is pertaining to a Visual C++ issue. The following code for deleting a Binary Tree works fine with GNU's C++ compiler.
Tree_Node Class Definition:
class Tree_Node
{
friend class Binary_Tree;
public:
typedef int node_type;
node_type& data()
{
return value;
}
void data(node_type key)
{
this->value = key;
}
Tree_Node(node_type key) : value(key) {}
~Tree_Node();
private:
node_type value = 0;
Tree_Node* right = nullptr;
Tree_Node* left = nullptr;
};
Binary Tree Destructor Definition:
Binary_Tree::~Binary_Tree()
{
deleteTree(root);
}
void Binary_Tree::deleteTree(Tree_Node* node)
{
if (node)
{
deleteTree(node->left);
deleteTree(node->right);
cout << node->data();
delete node;
}
}
However, while giving Visual C++ a try, the same code is giving out a couple of strange errors:
Error 1 error LNK2019: unresolved external symbol "public: __thiscall
Tree_Node::~Tree_Node(void)" (??1Tree_Node##QAE#XZ) referenced in
function "public: void * __thiscall Tree_Node::`scalar deleting
destructor'(unsigned int)" (??_GTree_Node##QAEPAXI#Z)
E:\Workspace\BinaryTree\BinaryTree\BinaryTree_Methods.obj
Error 2 error LNK1120: 1 unresolved externals
E:\Workspace\BinaryTree\Debug\BinaryTree.exe
The problem seems to be arising specifically from the delete node; statement. What am I missing here?
Did you make a destructor for node?
Like Declare and define ~Tree_Node()
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why can templates only be implemented in the header file?
Main class
int main() {
initCarList();
}
void initCarList() {
List<Car> carList;
Car c1 = Car("Toyota", "Bettle", 5);
carList.add(c1);
Car c2 = Car("Mercedes", "Bettle", 7);
carList.add(c2);
Car c3 = Car("FireTruck", "Large Van", 20);
carList.add(c3);
Car c4 = Car("Puma", "Saloon Car", 10);
carList.add(c4);
}
List class
#include "List.h"
#include <iostream>
using namespace std;
template <typename ItemType>
class List {
private:
ItemType itemList[10];
int size;
public:
List();
void add(ItemType);
void del(int index);
bool isEmpty();
ItemType get(int);
int length();
};
template<typename ItemType>
List<ItemType>::List() {
size = 0;
}
template<typename ItemType>
void List<ItemType>::add(ItemType item) {
if(size < MAX_SIZE) {
itemList[size] = item;
size++;
} else {
cout << typename << " list is full.\n";
}
}
I got errors like these
Error 3 error LNK2019: unresolved external symbol "public: void
__thiscall List::add(class Car)" (?add#?$List#VCar####QAEXVCar###Z) referenced in function "void
__cdecl initCarList(void)" (?initCarList##YAXXZ) C:\Users\USER\Desktop\New
folder\DSA_Assignment\main.obj DSA_Assignment
Did I do anything wrongly in my code? NEED HELP THANKS!
There is a syntax error (cout << typename ) in your code. I don't know how you got the linker error. May be its not being compiled at all.
otherwise its okay http://ideone.com/PGWGZu
Clearly you did as it doesn't work! Flippancy aside, let's take a look at the error message bit by bit:
Error 3 error LNK2019: unresolved external symbol
So this is a linkage error. The linker is trying to put together the units that were individually compiled together, but in this case it can't find an external symbol - usually a function or variable name.
"public: void __thiscall List::add(class Worker)" (?add#?$List#VWorker####QAEXVWorker###Z)
This is the full signature of the function that you're missing. It's name manged unfortunately but with your context knowledge of the code that you're writing, you should be able to tell that it's:
void List::add(Worker)
The next bit ...
referenced in function "void __cdecl initWorkerList(void)" (?initWorkerList##YAXXZ) C:\Users\USER\Desktop\New folder\DSA_Assignment\main.obj DSA_Assignment
... is telling you where the problem is happening, i.e where in the code it's trying to link, there is a reference to the missing function. Again, after demangling it's in:
void initWorkerList()
As you can see, with a bit of graft, you can determine exactly what you've done wrong here. Hope this helps.
I'm getting the following error while compiling this simple program using Visual Studio:
error LNK2019: unresolved external symbol "public: void __thiscall CoList<int>::enqueue(int)" (?enqueue#?$CoList#H##QAEXH#Z) referenced in function _main
error LNK2019: unresolved external symbol "public: virtual __thiscall CoList<int>::~CoList<int>(void)" (??1?$CoList#H##UAE#XZ) referenced in function _main
error LNK2019: unresolved external symbol "public: int __thiscall CoList<int>::dequeue(void)" (?dequeue#?$CoList#H##QAEHXZ) referenced in function _main
error LNK2019: unresolved external symbol "public: int __thiscall CoList<int>::count(void)" (?count#?$CoList#H##QAEHXZ) referenced in function _main
error LNK2019: unresolved external symbol "public: __thiscall CoList<int>::CoList<int>(void)" (??0?$CoList#H##QAE#XZ) referenced in function _main
error LNK1120: 5 unresolved externals
My program is very simple. I don't use external libraries, just the 'iostream' and 'exception' headers... Here is the full code:
CoList.h
#pragma once
#include "CoListItem.h"
template <class T>
class CoList
{
public:
CoList();
virtual ~CoList();
void enqueue(T value);
T dequeue();
T *peek();
int count();
private:
CoListItem<T> *m_root;
int m_count;
};
CoListItem.h
#pragma once
template <class T>
class CoListItem
{
public:
CoListItem();
virtual ~CoListItem();
T value;
CoListItem *next;
};
CoList.cpp
#include "CoList.h"
#include <exception>
template <class T>
CoList<T>::CoList()
{
}
template <class T>
CoList<T>::~CoList()
{
}
template <class T>
void CoList<T>::enqueue(T value)
{
if (this->m_root != NULL) {
this->m_root = new CoListItem<T>();
this->m_root->value = value;
this->m_root->next = NULL;
} else {
CoListItem<T> *tempitem = new CoListItem<T>();
tempitem->value = value;
tempitem->next = this->m_root;
this->m_root = tempitem;
}
this->m_count++;
}
template <class T>
T CoList<T>::dequeue()
{
if (this->m_root == NULL) {
throw std::exception();
} else {
T retval = this->m_root->value;
CoListItem *next = this->m_root->next;
delete this->m_root;
this->m_root = next;
return retval;
}
}
template <class T>
T *CoList<T>::peek()
{
if (this->m_root == NULL) {
return NULL;
} else {
return *this->dequeue();
}
}
template <class T>
int CoList<T>::count()
{
return this->m_count;
}
CoListItem.cpp
#include "CoListItem.h"
template <class T>
CoListItem<T>::CoListItem()
{
}
template <class T>
CoListItem<T>::~CoListItem()
{
}
and finally the main function:
#include <iostream>
#include "CoList.h"
#include "CoListItem.h"
using namespace std;
int main(int argc, char *argv[])
{
CoList<int> list;
for(int i = 0; i < 10; i++)
list.enqueue(i);
cout << "Count: " << list.count() << endl;
for(int i = 0; i < 10; i++)
cout << "Item: " << list.dequeue() << endl;
cout << "Count: " << list.count() << endl;
int wait = 0;
cin >> wait;
}
As you can see it is a very simple Queue implementation using a linked list...
The definitions of function templates(including member functions of class templates) must be in the .h file so that they are present in every cpp file in which they are used. That's how templates work. You cant put the definitions into a cpp file. Technically, there is an export keyword which enables this but since almost no implementation supported it it was removed in the new standard.
Read this: The inclusion model
template definitions should be visible to the code which is using it. For that,
Put all the definitions in ".h" file
Put the definitions in ".cpp" file (for the code separation) and
#include that ".cpp" file
For example, in your case you can #include "CoList.cpp" instead of "CoList.h". And so on.
Consider a template function that takes T and performs modulus (%), or a simple addition (+) for that matter.
template <class T>
T GetT(T t1, T t2)
{
return t1%t2;
}
You see NO ERROR in this code. Alright. When I pass two ints it gets compiled:
GetT(10,20);
But when I pass float/double it WONT compile:
GetT(10.6, 20.5);
Compiler will emit: error C2296: '%' : illegal, left operand has type 'double' and other related errors.
The point is that template code doesn't get compiled until you instantiate it at least once for a particular data type. The template code stays junk - compiler doesn't care what actually inside the code. In your case the CPP is nothing but a text-file the compiler has ignored - All of it.
Having said that, when I use operator +, instead of operator % it would work for all basic data-types, but not for classes that are missing operator +. In that case compiler will compile again the template-stuff for that data-type (the class).
There are cases where compiler and linker work together to reduce final binary code size, when they see some code is duplicate and would be same for all/several data-types. But that's a different case.
This is straight from Nicolai Josutis's legendary book,
C++ Templates: A complete Guide
Templates are compiled twice:
Without instantiation, the template itself is checked for correct syntax, Syntax errors such as semicolon are discovered here.
As the time of instantiation, the templates code is checked to ensure that all calls are valid. Invalid calls are discovered such as unsupported function calls.
This leads to an important problem in the handling of templates practice. When a function template is used in a way that it triggers instantiation, a compiler will (at some point) need to see that template definition. This breaks the usual compile and link distinction for functions, when declaration of function is sufficient to compile the its use.
Thus, For a template the declaration and definition should be kept in the same header file so that they are visible in every cpp which uses them.
[[UPDATE]] -> If I #include "Queue.cpp" in my program.cpp, it works just fine. This shouldn't be necessary, right?
Hey all -- I'm using Visual Studio 2010 and having trouble linking a quick-and-dirty Queue implementation. I started with an empty Win32 Console Application, and all files are present in the project. For verbosity, here's the complete code to duplicate my error. I realize some of the code may, in fact, be wrong. I haven't had a chance to test it yet because I haven't yet been able to link it.
Queue.hpp
#ifndef ERROR_CODE
#define ERROR_CODE
enum Error_Code
{
Success,
Underflow,
Overflow
};
#endif // ERROR_CODE
#ifndef QUEUE
#define QUEUE
template<class T>
struct Queue_Node
{
T data;
Queue_Node *next;
Queue_Node()
{
next = NULL;
}
Queue_Node(T pData)
{
data = pData;
next = NULL;
}
Queue_Node(T pData, Queue_Node *pNext)
{
data = pData;
next = pNext;
}
};
template<class T>
class Queue
{
public:
Queue();
Error_Code Serve();
Error_Code Append(T item);
T Front();
~Queue();
private:
void Rescursive_Destroy(Queue_Node<T> *entry);
Queue_Node<T> *front, *rear;
};
#endif // QUEUE
Queue.cpp
#include "Queue.hpp"
template <class T>
Queue<T>::Queue()
{
this->front = this->rear = NULL;
}
template<class T>
Error_Code Queue<T>::Serve()
{
if(front == NULL)
return Underflow;
Queue_Node *temp = this->front;
this->front = this->front->next;
delete temp;
}
template<class T>
Error_Code Queue<T>::Append(T item)
{
Queue_Node *temp = new Queue_Node(item);
if(!temp)
return Overflow;
if(this->rear != NULL)
this->rear->next = temp;
this->rear = temp;
return Success;
}
template<class T>
T Queue<T>::Front()
{
if(this->front == NULL)
return Underflow;
return this->front->data;
}
template<class T>
Queue<T>::~Queue()
{
this->Rescursive_Destroy(this->front);
}
template<class T>
void Queue<T>::Rescursive_Destroy(Queue_Node<T> *entry)
{
if(entry != NULL)
{
this->Recursive_Destroy(entry->next);
delete entry;
}
}
program.cpp
#include "Queue.hpp"
int main()
{
Queue<int> steve;
return 0;
}
And the errors...
Error 1 error LNK2019: unresolved external symbol "public: __thiscall Queue<int>::~Queue<int>(void)" (??1?$Queue#H##QAE#XZ) referenced in function _main C:\[omitted]\Project2_2\Project2_2\program.obj Project2_2
Error 2 error LNK2019: unresolved external symbol "public: __thiscall Queue<int>::Queue<int>(void)" (??0?$Queue#H##QAE#XZ) referenced in function _main C:\[omitted]\Project2_2\Project2_2\program.obj Project2_2
Why don't you follow the "Inclusion Model"? I'd recommend you follow that model.
The compiler needs to have access to the entire template definition (not just the signature) in order to generate code for each instantiation of the template, so you need to move the definitions of the functions to your header.
Note: In general most C++ compilers do not easily support the separate compilation model for templates.
Furthermore you need to read this.
An example for solving the error lnk2019:
It has to write #include "EXAMPLE.cpp" at the end of .h file
//header file codes
#pragma once
#ifndef EXAMPLE_H
#define EXAMPLE_H
template <class T>
class EXAMPLE
{
//class members
void Fnuction1();
};
//write this
#include "EXAMPLE.cpp"
#endif
//----------------------------------------------
In the .cpp file do as following
//precompile header
#include "stdafx.h"
#pragma once
#ifndef _EXAMPLE_CPP_
#define _EXAMPLE_CPP_
template <class T>
void EXAMPLE<T>::Fnuction1()
{
//codes
}
#endif
//-----------------------------------------------
All template code need to be accessible during compilation. Move the Queue.cpp implementation details into the header so that they are available.
The linker errors are because it sees the header files for Queue.hpp, but doesn't see the definitions of the functions. This is because it is a template class, and for C++, the definitions of templates must be in the header file (there are a few other options, but that is the easiest solution). Move the defintions of the functions from Queue.cpp to Queue.hpp and it should compile.
If you have:
template <typename T>
void foo();
And you do:
foo<int>();
The compiler needs to generate (instantiate) that function. But it can't do that unless the function definition is visible at the point of instantiation.
This means template definitions needs to be included, in some way, in the header. (You can include the .cpp at the end of the header, or just provide the definitions inline.)