This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 8 years ago.
In my main I create an object from a template class, then I call my sort method (template method)
However it get a error in my main.obj file.
error:
LNK2019: unresolved external symbol "public: void __thiscall SelectionSort<int [0]>::IterativeSort(int * const,unsigned int)" ............
Call in main:
SelectionSort<int[]> smallArraySort;
smallArraySort.IterativeSort(smallArray, smallSize);
Header file: SelectionSort.h
template <class T>
class SelectionSort
{
public:
void IterativeSort(T data, unsigned int size);
void RecursiveSort(T data, unsigned int size);
};
sort code: SelectionSort.cpp
#include "SelectionSort.h"
template<class T>
void SelectionSort<T> ::IterativeSort(T data, unsigned int size)
{
int temp = data[0];
int greaterNum = 0
for (unsigned int index = 0; index < size; index++)
{
for (unsigned int inner = index; inner < size; inner++)
{
if (temp>data[inner])
{
greaterNum = temp;
temp = data[inner];
data[inner] = greaterNum;
}
}
}
}
This happens because you implement the methods of the template in a .cpp file where they cannot be seen when they need to be instantiated. In general, templates must be defined in a header file.
To solve the problem, eliminate your SelectionSort.cpp file by moving its definitions into SelectionSort.h.
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.
So this part of the code is a small part of a large project. I can't copy the entire project but it's really just 2 lines making the error. I'm trying to access the function "mergeSort" from the class Metrics. Metrics is a different class than the one I'm trying to access it in. I've defined mergeSort and also #included Metrics in the class I'm working with. I've also defined the constructor. Here is the piece of code:
void Document::createHashWords()
{
Node* heads[97];
string* allWords = parseWords();
int numWords = getdWordCt();
for ( int i = 0; i < numWords; i++ )
{
char* word = (char*)allWords[i].c_str();
int k = hashWord(word,97);
insertWord(heads,k,allWords[i]);
}
for ( int i = 0; i < 97; i++ )
{
Node* temp = heads[i];
int size = 0;
while (temp != NULL)
{
size++;
temp = temp->getNext();
}
int* countArr = new int[size];
temp = heads[i];
for ( int i = 0; i < size; i++ )
{
countArr[i] = temp->getCount();
temp = temp->getNext();
}
Metrics <int> toSort;
toSort.mergeSort(countArr,size);
}
}
the Code that is causing the problem is the last 2: Metrics toSort and toSort.mergeSort(countArr,size);.
Here is the Metrics class:
template <class T>
class Metrics
{
private:
int id;
public:
Metrics();
~Metrics();
void selectionSort(T *arr, int n);
void insertionSort(T *arr, int n);
void merge(T *a, int numA, T *b, int numB, T *c);
void mergeSort(T *arr, int n);
};
I've defined mergeSort in the .cpp file for that class.
Here is my build error:
1>Document.obj : error LNK2019: unresolved external symbol "public: __thiscall Metrics<int>::Metrics<int>(void)" (??0?$Metrics#H##QAE#XZ) referenced in function "public: void __thiscall Document::createHashWords(void)" (?createHashWords#Document##QAEXXZ)
1>Document.obj : error LNK2019: unresolved external symbol "public: __thiscall Metrics<int>::~Metrics<int>(void)" (??1?$Metrics#H##QAE#XZ) referenced in function "public: void __thiscall Document::createHashWords(void)" (?createHashWords#Document##QAEXXZ)
1>Document.obj : error LNK2019: unresolved external symbol "public: void __thiscall Metrics<int>::mergeSort(int *,int)" (?mergeSort#?$Metrics#H##QAEXPAHH#Z) referenced in function "public: void __thiscall Document::createHashWords(void)" (?createHashWords#Document##QAEXXZ)
1>C:\Users\Kevin\Documents\Visual Studio 2012\Projects\CMPSC 122 Checkpoint 2\Debug\CMPSC 122 Checkpoint 1.exe : fatal error LNK1120: 3 unresolved externals
If I remove those 2 lines, I can compile fine. I just don't know why those 2 lines are wrong. I need to access that function from the Metrics class.
template <class T>
class Metrics
{
private:
int id;
public:
Metrics<T>() {}
~Metrics<T>() {}
void selectionSort(T *arr, int n);
void insertionSort(T *arr, int n);
void merge(T *a, int numA, T *b, int numB, T *c);
void mergeSort(T *arr, int n);
};
So this is now my Metrics class:
template <class T>
class Metrics
{
private:
int id;
public:
Metrics() {}
~Metrics() {}
void selectionSort(T *arr, int n);
void insertionSort(T *arr, int n);
void merge(T *a, int numA, T *b, int numB, T *c);
void mergeSort(T *arr, int n);
};
I commented out the definitions of the constructor/destructor in the Metrics.cpp file like so:
//template <class T>
//Metrics<T>::Metrics()
//{
//}
//template <class T>
//Metrics<T>::~Metrics()
//{
//}
And now this is my error code:
1>Document.obj : error LNK2019: unresolved external symbol "public: void __thiscall Metrics::mergeSort(int *,int)" (?mergeSort#?$Metrics#H##QAEXPAHH#Z) referenced in function "public: void __thiscall Document::createHashWords(void)" (?createHashWords#Document##QAEXXZ)
1>C:\Users\Kevin\Documents\Visual Studio 2012\Projects\CMPSC 122 Checkpoint 2\Debug\CMPSC 122 Checkpoint 1.exe : fatal error LNK1120: 1 unresolved externals
The missing symbol seems to be the default ctor for Metrics, the one that takes no arguments. Have you defined it? You need to get it included somehow in the same translation unit. The usual way would be to define it in the header file:
template <typename T>
Metrics<T>::Metrics() {}
Template functions need to be defined in every translation unit (.cpp) they're used in, so you want all of Metrics' member functions to be defined in Metrics.h, as if they were all inlined.
They work differently from normal functions because the code generated is different for every different type used for T, so the compiler can't know what versions to generate when compiling Metrics.cpp.
While instantiating the class in main I am getting these two errors:
error LNK2019: unresolved external symbol "public: __thiscall templateClass<int>::templateClass<int>(void)" (??0?$templateClass#H##QAE#XZ) referenced in function _wmain
error LNK2019: unresolved external symbol "public: __thiscall templateClass<int>::~templateClass<int>(void)" (??1?$templateClass#H##QAE#XZ) referenced in function _wmain
Code
templateClass.h
#pragma once
#define MAX 10
template<class T>
class templateClass
{
private:
T arr[MAX];
int size;
public:
templateClass(void);
void initArrayWithZero();
void pushElementIntoArray(T element );
void printArray();
~templateClass(void);
};
templateclass.c
#include "templateClass.h"
template <class T>
templateClass<T>::templateClass(void)
{
size = 0;
}
template <class T>
templateClass<T>::~templateClass(void)
{
}
template <class T>
void templateClass<T>::pushElementIntoArray(T element )
{
if(size<MAX)
{
T[size++] = element;
}
else
{
//Give error code
}
}
template <class T>
void templateClass<T>::initArrayWithZero()
{
for(i= 0; i<MAX; i++)
T[i] = 0;
}
template <class T>
void templateClass<T>::printArray()
{
for( int i =0; i<MAX; i++)
cout<<"\n"T[i];
}
Main.cpp
#include "stdafx.h"
#include "templateClass.h"
int _tmain(int argc, _TCHAR* argv[])
{
templateClass<int> intarray;
return 0;
}
How can I fix this?
Template classes such as templateClass<T> must (usually) be implemented in header (.h) files.
As such, you need to move the content of templateclass.c to templateClass.h and delete templateclass.c.
See Why can templates only be implemented in the header file? for more information.
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Why do I get "unresolved external symbol" errors when using templates? [duplicate]
(3 answers)
Closed 9 years ago.
I have 3 files - main, Array.hh, and Array.cc. When I do "g++ main.cc Array.cc", I get all kinds of linker errors, e.g.: "undefined reference to Array<<\double>>::Array(int)"
I read the other stackoverflow entries for linker errors with templates, but they are recommending to split the HH and CC files, which I have already done. So what can be the problem here?
Edit: Thanks for the replies. I had not understood the posts I had read previously. Merging the Array.cc into the Array.hh solves the problem. Closed.
main.cc:
#include "Array.hh"
#include <iostream>
int main() {
Array<int> anArray(12);
Array<double> adArray(12);
for (int nCount = 0; nCount < 12; nCount++) {
anArray[nCount] = nCount;
adArray[nCount] = nCount + 0.5;
}
for (int nCount = 11; nCount >= 0; nCount--)
std::cout << anArray[nCount] << "\t" << adArray[nCount]
<< std::endl;
return 0;
}
Array.hh:
template <typename T>
class Array {
private:
int m_nLength;
T *m_ptData;
public:
Array();
Array(int nLength);
~Array();
void Erase();
T& operator[](int nIndex);
int GetLength();
};
Array.cc
#include "Array.hh"
template <typename T>
Array<T>::Array() {
m_nLength = 0;
m_ptData = 0;
}
template <typename T>
Array<T>::Array(int nLength) {
m_ptData= new T[nLength];
m_nLength = nLength;
}
template <typename T>
Array<T>::~Array() { delete[] m_ptData; }
template <typename T>
void Array<T>::Erase() {
delete[] m_ptData;
m_ptData= 0;
m_nLength = 0;
}
template <typename T>
int Array<T>::GetLength() { return m_nLength; }
Put the definitions from Array.cc into Array.hh
When a template class is used, a class is created. Array.cc does not know which classes should be created from the template, only main.cc knows that. main.cc does not know how to create the classes, because it does not know the definition of the member functions of Array, only Array.cc knows that.
You need to #include "Array.cc"
A template can't be instantiated if its definition is not available.
This separation of definition and declaration is fine, but you must include the cc file whereever you are instatiating that template with a new type
Recommendations you took are not very accurate. You should not separate your templates into .h and .cpp files.
If you insist on putting them separate, "export" is the keyword you are looking for.
For more information about "export" check here: http://www.parashift.com/c++-faq/separate-template-fn-defn-from-decl-export-keyword.html.
I have created a template class that is supposed to store a grid as a 2-dimensional std::vector; however, when I compile, using VC++ (2010 if it matters, but I doubt it) I get the following error:
unable to match function definition to an existing declaration
Even though the two functions it is trying to match are exactly equal.
Here is the code in the header file:
#pragma once
#include "CBlock.h"
template<class T>
class CMyGrid{
public:
long sizeX;
long sizeY;
/*block position on grid*/
std::vector<std::vector<T*>> System;
CMyGrid();
~CMyGrid();
CMyGrid(int sizeXp, int sizeYp){sizeX = sizeXp; sizeY =sizeYp;};
void Set(T *data, int x, int y){System.at(x).at(y) = data;};
int GetSizeX(){return sizeX;}
int GetSizeY(){return sizeY;}
int getxPosition(T *data); /*make easier put in struct*/
int getyPosition(T *data);
/*size*/ /* will hopefully be sizex by sizey*/
};
And here is the cpp file:
#include "stdafx.h"
#include "CMyGrid.h"
#include "CBlock.h"
template <class T>
template <class T>
int CMyGrid<T>::getxPosition(T *data)
{
for (int i = 0; i <System.size(); i++)
{
for (int j = 0; j < System[i].size(); j++)
{
if data == System[i][j];
return j;
else
continue;
}
}
}
template <class T>
int CMyGrid<T>::getyPosition(T *data)
{
for (int i = 0; i <System.size(); i++)
{
for (int j = 0; j < System[i].size(); j++)
{
if data == System[i][j];
return i;
else
continue;
}
}
}
Here's the entire error:
1>c:\users\chris\documents\visual studio 2010\projects\testtest\testtest\cmygrid.cpp(33): error C2244: 'CMyGrid::getxPosition' : unable to match function definition to an existing declaration
1> c:\users\chris\documents\visual studio 2010\projects\testtest\testtest\cmygrid.h(18) : see declaration of 'CMyGrid::getxPosition'
1> definition
1> 'int CMyGrid::getxPosition(T *)'
1> existing declarations
1> 'int CMyGrid::getxPosition(T *)'
I have read several other threads with similar problems, and have gotten as far as changing the error to a linker error which I get if I include the function code for the two getposition functions in the header file alongside the declaration. The linker error is:
1>CBoard.obj : error LNK2019: unresolved external symbol "public: __thiscall CMyGrid::CMyGrid(void)" (??0?$CMyGrid#VCBlock####QAE#XZ) referenced in function "public: __thiscall CBoard::CBoard(void)" (??0CBoard##QAE#XZ)
1>CBoard.obj : error LNK2019: unresolved external symbol "public: __thiscall CMyGrid::~CMyGrid(void)" (??1?$CMyGrid#VCBlock####QAE#XZ) referenced in function "public: __thiscall CBoard::~CBoard(void)" (??1CBoard##QAE#XZ
The problem is that you can't have the implementation of a template in the .cpp.
Try to change your code into the .h
Here you have a big post explaining this.
Storing C++ template function definitions in a .CPP file