This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 5 years ago.
Let's say we have base class Table
template <typename T>
class Table
{
public:
Table();
virtual ~Table() = default;
private:
// get all column names as list
virtual std::list<std::string> getAllColumnsImpl();
};
and I want inherit TestTable class and override method getAllColumnsImpl from base class:
class TestTable :
public Table<TestTable>
{
public:
TestTable();
virtual ~TestTable() = default;
std::string Description;
int Count;
private:
// get all column names as list
std::list<std::string> getAllColumnsImpl() override;
};
Is it possible in general ?
For example I have linker errors like:
error LNK2019: unresolved external symbol "public: __cdecl Table<class TestTable>::Table<class TestTable>(void)" (??0?$Table#VTestTable####QEAA#XZ) referenced in function "public: __cdecl TestTable::TestTable(void)" (??0TestTable##QEAA#XZ)
You can do it, it's called CRTP - the Curiously Recurring Template Parameter. It's very handy and there are many blogs and resources explaining uses for it.
The error you're getting is because you need to have the template's function bodies in the template's header file.
Each cpp file is compiled to a separate object file, and templates are resolved on a per-cpp file basis. When you put template code in a cpp file, then it's just "template < T >" and the compiler doesn't know what T is, so no code is generated (unless it's requested from the same cpp file, with an actual type and not T).
However, your other cpp file knows that it wants a "template < TestTable >", but it doesn't have access to the code that would make that work, because that's stuck in the other cpp file, which only knows the generic "template < T >". Neither cpp file is able to generate the missing code, so you get the linker error. Putting all the template code together in the header file removes the issue.
Related
This question already has answers here:
static variable link error [duplicate]
(2 answers)
Closed 2 years ago.
I'm trying to make a text-based console video game in c++.
I have an Inventory class with a header and a source file. In the same header file I have declared a struct called STRINGSIZES with two integer members called name and description. They are used to store the length that should be used when displaying the Items, or from which length the name will be shortened. The header file "Inventory.h" looks something like this:
#pragma once
#include <iostream>
struct STRINGSIZES { //the fixed Size with which Inventory lists will be printed
int name;
int description;
};
class Inventory
{
public:
//some unrelated code
Inventory();
static void setStringSizes(int name, int description);
private:
static STRINGSIZES stringSizes;
};
In the Inventory.cpp file, I define the setStringSizes() method like so:
void Inventory::setStringSizes(int name, int description)
{
stringSizes.name = name;
stringSizes.description = description;
}
In my main Source.cpp file, I am firstly calling this method.
Now when I try to compile this I get the errors:
1>Inventory.obj : error LNK2001: unresolved external symbol "public: static int stringSizeNames::name" (?name#stringSizeNames##2HA)
1>Inventory.obj : error LNK2001: unresolved external symbol "public: static int stringSizeNames::description" (?description#stringSizeNames##2HA)
What is the problem here?
The error message refers to a variable which declaration you did not show in the question. But I think it is the same problem as with the static data member stringSizes.
Within the class definition this data member
static STRINGSIZES stringSizes;
is a declaration that is not a definition.
You have to define it outside the class definition in the cpp file for example like
STRINGSIZES Inventory::stringSizes;
If your compiler supports the C++17 Standard then you could define the data member inside the class definition the following way
class Inventory
{
//...
inline static STRINGSIZES stringSizes = {};
};
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 6 years ago.
I know this problem may occur when I declare function and not define it.
But this is not the case.
//In the 'H' file. Template class.
BSNode(T data);
\\In the cpp definitions
template <class T>
BSNode<T>::BSNode(T data)
{
_root = this;
_data = data;
_right = NULL;
_left = NULL;
}
And still, I get the next Error:
Error 1 error LNK2019: unresolved external symbol "public: __thiscall BSNode<int>::BSNode<int>(int)" (??0?$BSNode#H##QAE#H#Z) referenced in function _main c:\Users\a\OneDrive\ss\visual studio 2013\Projects\Project5\2\Source.obj 2_TREES
What also may cause this Error to occur if its not the incompatibility between the 'H' and the 'cpp' files?
The code that uses this constructor with the int instantiation should also be in the .cpp file. The compiler needs it to generate the instance of the code, because it cannot generate all possible instances.
Several solutions:
move at least one use of the constructor with the int instance in the cpp file
rename the .cpp file into a .template file that you can include in every file that uses the BSNode instances.
add template class BSNode<int>; in the .cpp file to force the template instantiation.
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 9 years ago.
Is it possible to pass the template-parameters to a function somewhere else defined?
For instance I have the class
Barrier.pp
template<Location L, Knock K>
class Barrier
{
//...
void checkBarrier( ... )
{
BarrierBest_checkBarrier<L, K>( ... );
}
//...
}
Other.cpp
template<Location L, Knock K>
BarrierBest_checkBarrier( ... )
{
//Use L and K to do call other function
}
As I have it right now the compiler throws a unresolved external symbol for all the possible combinations of the template parameters, that is, BarrierBest_checkBarrier<1,1>, BarrierBest_checkBarrier<1,0>, BarrierBest_checkBarrier<0,1>, BarrierBest_checkBarrier<0,0>
Is there a way to make this work?
If there are a limited number of combinations, you can explicitly instantiate your template, allowing you to keep your code separated between header and source files.
Put this at the bottom of your source file
template void BarrierBest_checkBarrier<0, 0>(...);
template void BarrierBest_checkBarrier<0, 1>(...);
template void BarrierBest_checkBarrier<1, 0>(...);
template void BarrierBest_checkBarrier<1, 1>(...);
If you want other files calling your function to pick their own parameters not in this list, you must put the whole templated code into a header file.
The problem may be that your templated functions are in cpp files, not in headers. The template parameters have to be known at the compile time. If you have separate compilation units, they are not.
So, I've created a basic VC++ program, and created a template class with 1 method (besides the constructor and destructor). I'm getting the following errors:
>main.obj : error LNK2019: unresolved external symbol "public: __thiscall Vector<int>::~Vector<int>(void)" (??1?$Vector#H##QAE#XZ) referenced in function _main
>main.obj : error LNK2019: unresolved external symbol "public: __thiscall Vector<int>::Vector<int>(int)" (??0?$Vector#H##QAE#H#Z) referenced in function _main
>c:\users\edy\documents\visual studio 2010\Projects\ex01\Debug\ex01.exe : fatal error LNK1120: 2 unresolved externals
Here is my code:
(CPP Class file)
using namespace std;
#include "Vector.h"
template <class T> Vector<T>::Vector(int n)
{
this.crt = 0;
this.dim = n;
this.elem = new T[100];
}
template <class T> void Vector<T>::add(T e)
{
this.elem[crt] = e;
this.crt++;
}
template <class T> Vector<T>::~Vector(void)
{
this.crt = 0;
}
(H Class file)
#pragma once
template <class T> class Vector
{
public:
int dim;
T* elem;
Vector(int n);
void add(T e);
~Vector(void);
private:
int crt;
};
(Main file)
using namespace std;
#include "Vector.h"
int main(void)
{
Vector<int> x(5);
//x.add(1); <--- if i decomment this line, it throws an additional error
return 0;
}
Most solutions involved not implemented methods, but I have all my methods implemented. I have no idea what could be wrong. Any help?
Template class implementation need to be visible to all translation units that use them. Move the implementations to the header file.
Before you ask - no, there's no way to hide them, unless you know in advance which specializations for the class you have. If you want your Vector to be generic, the implementations need to be visible.
If you want to separate them, to usual way to go about it is to have the implementations in a .impl file which you include in the header.
If you intend to implement the template in a .cpp file, you will need to provide an explicit instantiation of the template there as well. You can add to the template's .cpp file:
class template Vector<int>;
at the bottom. This will instantiate an int version of your vector template. But, you will find your template easier to use if you follow Luchian's advice. If you do as he suggests, the compiler will create the instantiations on demand for you as you use Vector<> on different types. If you leave it in a .cpp file, you will have to add an explicit instantiation each time you want to create a different kind of Vector<>.
Some think explicit instantiation is "leaner" than implicit, because if different sets of object files use the same template instantiations many times, the compiler may be creating just as many instantiations. However, the linker will remove the duplicate instantiations in the end when the executable is linked together. Even so, the bloat still persists if multiple shared libraries have reused the same template with the same parameters, even though the dynamic linker will clean it up. If executable loading time is important, this may be a reason to prefer explicit instantiation. If you have a very large project, and build and link times are an issue, this may also be a reason to prefer explicit instantiation.
Otherwise, you should stick with implicit instantiation.
I have a problem with generics in c++.I have two Matrix.h and Matrix.cpp files.Here is files:
#pragma once
template<class T>
class Matrix
{
public:
static T** addSub(int size,T** firstMatrix,T** secondMatrix,int operation);
}
and Matrix.cpp
#include "Martix.h"
template<class T>
static T** Matrix<T>::addSub( int n,T **firstMatrix,T **secondMatrix,int operation)
{
//variable for saving result operation
T **result = new T*[n];
//create result matrix
for( int i=0;i<n;i++)
result[i] = new T[n];
//calculate result
for( int i=0;i<n;i++)
for(int j=0;j<n;j++)
result[i][j] =
(operation == 1) ? firstMatrix[i][j] + secondMatrix[i][j]:
firstMatrix[i][j] - secondMatrix[i][j];
return result;
}
when I run these I get the below error:
Error 1 error LNK2019: unresolved external symbol "public: static int * * __cdecl Matrix<int>::addSub(int,int * *,int * *,int)" (?addSub#?$Matrix#H##SAPAPAHHPAPAH0H#Z) referenced in function "public: static int * * __cdecl Matrix<int>::strassenMultiply(int,int * *,int * *)" (?strassenMultiply#?$Matrix#H##SAPAPAHHPAPAH0#Z) C:\Users\ba.mehrabi\Desktop\Matrix\matrixMultiplication\main.obj matrixMultiplication
what is the problem?
Unfortunately, you can't have the declaration of a template class in the *.cpp files. The full definition has to stay in the header file. This is a rule of many C++ compilers.
See this: http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12
A template is not a class or a function. A template is a "pattern"
that the compiler uses to generate a family of classes or functions.
In order for the compiler to generate the code, it must see both
the template definition (not just declaration) and the specific
types/whatever used to "fill in" the template. For example, if you're
trying to use a Foo, the compiler must see both the Foo template
and the fact that you're trying to make a specific Foo.
Your compiler probably doesn't remember the details of one .cpp
file while it is compiling another .cpp file. It could, but most do
not and if you are reading this FAQ, it almost definitely does not.
BTW this is called the "separate compilation model."
The link has a workaround, but keep in mind that a template is a glorified macro so the header file is probably the best place for it.
The poster of this SO post shows a demonstration of the workaround.
First of all, the definition of functions of a class template, should go in the header itself.
Second, if you define the static member function out of class (though in the header itself), then don't use the static keyword (in the definition). It only needed in the declaration only.
Add
template Matrix<int>;
at the end of your cpp file and it will work. But you need to learn a few things about templates, otherwise you'll have to deal with lots of issues you don't understand.