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
Related
I have a header file, defining the chunk class:
#pragma once
#include <vector>
#include "Tile.h"
#include "Numerics.h"
namespace boch {
class chunk {
public:
chunk();
static const uint defsize_x = 16;
static const uint defsize_y = 16;
std::vector<std::vector<tile*>> tilespace;
tile* getat(vint coords);
void fillc(tile t);
};
}
Then, I defined the implementation of the class in Chunk.cpp file:
#include "Chunk.h"
boch::chunk::chunk() {
tilespace = std::vector<std::vector<tile*>>(defsize_x);
for (int x = 0; x < defsize_x; x++) {
std::vector<tile*> temp = std::vector<tile*>(defsize_y);
tilespace[x] = temp;
}
}
void boch::chunk::fillc(tile t) {
for (int x = 0; x < defsize_x; x++) {
for (int y = 0; y < defsize_y; y++) {
tilespace[x][y] = new tile(t);
}
}
}
boch::tile* boch::chunk::getat(vint coords) {
return tilespace[coords.x][coords.y];
}
(vint is a typedef of boch::vector<int> which is the custom X,Y vector, if that helps)
Then, I use it in the main function in BochGrounds.cpp file:
#include <iostream>
#include "Layer.h"
#include "Gamegrid.h"
int main()
{
boch::layer newlayer = boch::layer(boch::vuint(16, 16));
boch::chunk newchunk = boch::chunk();
boch::gamegrid newgrid = boch::gamegrid();
newchunk.fillc(boch::tile());
newgrid.addchunk(boch::cv_zero, &newchunk);
newgrid.drawtolayer(&newlayer);
newlayer.draw(std::cout);
}
Tile class defines the gamegrid class, chunk includes tile class, gamegrid includes chunk & entity (which includes tile as well). Layer class includes only tile. All header files have #pragma once directive. When trying to compile, I'm getting the following error:
LNK2019 unresolved external symbol "public: __cdecl boch::chunk::chunk(void)" (??0chunk#boch##QEAA#XZ) referenced in function main
LNK2019 unresolved external symbol "public: void __cdecl boch::chunk::fillc(class boch::tile)" (?fillc#chunk#boch##QEAAXVtile#2##Z) referenced in function main
and as the result:
LNK1120 2 unresolved externals
Other StackOverflow answers suggest that the linker cannot see implementations of both fillc() and chunk constructor functions, but I cannot see why if it is even the problem here. Please help. (Linker settings haven't been changed, and are default for MVSC 2019)
Thanks sugar for the answer. I deleted both header and .cpp files and readded them, and it worked like a charm. I suppose I have added either header or .cpp file just by directly adding a new file to the header/source folder instead of adding it to the project (RMB click on the project > add new item).
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.
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.
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.