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.
Related
I'm trying to build a simple heap data structure for practice. When I build the version for double it works fine.
class heapt {
public:
heapt();
heapt(std::initializer_list<double> lst);
void print_heapt();
private:
int size;
int length;
double* elem; //points to root
};
Its constructors works perfectly and the heap is printed as it should. But when I try to generalize it with
template< typename Elem>
as:
template<typename Elem>
class heapt {
public:
heapt();
heapt(std::initializer_list<Elem> lst);
void print_heapt();
private:
int size;
int length;
Elem* elem; //points to root
};
for the class definition and as:
template<typename Elem>
heapt<Elem>::heapt(std::initializer_list<Elem> lst) :
size{ static_cast<int>(lst.size()) },
elem{new Elem[lst.size()]}
{
std::copy(lst.begin(), lst.end(), elem);//Now heaptify elem
build_heapt(elem, lst.size());
}
for one of the constructors used in the main function.
I get two linking errors:
LNK2019 unresolved external symbol "public: void __thiscall heapt::print_heapt(void)" (?print_heapt#?$heapt#H##QAEXXZ) referenced in function _main
LNK2019 unresolved external symbol "public: __thiscall heapt::heapt(class std::initializer_list)" (??0?$heapt#H##QAE#V?$initializer_list#H#std###Z) referenced in function _main
The main function is:
{
heapt<int> hh{ 27,12,3,13,2,4,14,5 };
std::cout << "Hello" << '\n';
hh.print_heapt();
}
EDIT: The heapt class is in the "heap.h" file and the definition for the constructor heapt<Elem>::heapt(std::initializer_list<Elem> lst) is in the "heap.cpp" class, which has #include"heap.h" as a header file. The int main function is in a file named "InSo.cpp", which also has #include"heap.h" as a header file.
In your templated class declaration you are using heapt(std::initializer_list<double> lst); but in your definition you are using std::initializer_list<Elem>. You should change the declaration to heapt(std::initializer_list<Elem> lst);
You are still missing definitions for print_heapt and build_heapt but otherwise it should compile.
EDIT: In light of you clarifying how your source files are set up, see WhozCraig's comment on your initial post. You can either include the definition of the templated class functions in a heap.hpp file, for example, and include it at the end of your heap.h, or just put them all together in one file, e.g.
// heap.h
#ifndef HEAP_H
#define HEAP_H
#include <initializer_list>
template<typename Elem>
class heapt {
public:
heapt();
heapt(std::initializer_list<Elem> lst);
void print_heapt();
private:
int size;
int length;
Elem* elem; //points to root
};
#include "heap.hpp"
#endif
//heap.hpp
#ifndef HEAP_HPP
#define HEAP_HPP
#include "heap.h"
#include <algorithm>
template<typename Elem>
heapt<Elem>::heapt(std::initializer_list<Elem> lst) :
size{ static_cast<int>(lst.size()) },
elem{ new Elem[lst.size()] }
{
std::copy(lst.begin(), lst.end(), elem);//Now heaptify elem
//build_heapt(elem, lst.size());
}
#endif
This question already has answers here:
Why do I get "unresolved external symbol" errors when using templates? [duplicate]
(3 answers)
Closed 7 years ago.
I am trying to implement a few classes but i got the following error when compiling the codes. I have tried to removed all the redundant codes but none of them helps. I have no idea what went wrong.
Here is the error i get when compile the code:
Severity Code Description Project File Line
Error LNK2019 unresolved external symbol "public: __thiscall FullArray<int>::FullArray<int>(unsigned int)" (??0?$FullArray#H##QAE#I#Z) referenced in function _wmain FinancialDerivatives C:\Users\Jeremy Nguyen\Documents\Visual Studio 2015\Projects\FinancialDerivatives\FinancialDerivatives\FinancialDerivatives.obj 1
Error LNK1120 2 unresolved externals FinancialDerivatives C:\Users\Jeremy Nguyen\Documents\Visual Studio 2015\Projects\FinancialDerivatives\Debug\FinancialDerivatives.exe 1
Error LNK2019 unresolved external symbol "public: virtual __thiscall FullArray<int>::~FullArray<int>(void)" (??1?$FullArray#H##UAE#XZ) referenced in function _wmain FinancialDerivatives C:\Users\Jeremy Nguyen\Documents\Visual Studio 2015\Projects\FinancialDerivatives\FinancialDerivatives\FinancialDerivatives.obj 1
FullArray.h file:
#pragma once
#include <vector>
template <class V>
class FullArray
{
private:
std::vector<V> m_vector; // Use STL vector class for storage
public:
// Constructors & destructor
FullArray();
FullArray(size_t size);
FullArray(const FullArray<V>& source);
FullArray<V>& operator = (const FullArray<V>& source);
virtual ~FullArray();
};
FullArray.cpp file:
#include "stdafx.h"
#include "FullArray.h"
template<class V>
FullArray<V>::FullArray()
{
m_vector = std::vector<V>(1); // vector object with 1 element
}
template<class V>
FullArray<V>::FullArray(size_t size)
{
m_vector = std::vector<V>(size);
}
template<class V>
FullArray<V>::FullArray(const FullArray<V>& source)
{
m_vector = source.m_vector;
}
template<class V>
FullArray<V>& FullArray<V>::operator=(const FullArray<V>& source)
{
// Exit if same object
if (this == &source) return *this;
// Call base class constructor
//ArrayStructure<V>::operator = (source);
// Copy the embedded vector
m_vector = source.m_vector;
return *this;
}
template<class V>
FullArray<V>::~FullArray()
{
}
main file:
#include "stdafx.h"
#include "FullArray.h"
int _tmain(int argc, _TCHAR* argv[])
{
FullArray<int> tmp(5);
return 0;
}
If you compile templates, the source needs to be available at any place where they are used, so include your .cpp file at the bottom of the .h file, or include the .cpp file instead of the .h file.
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 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
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.