I have 3 C++ files:
genericStack.h:
template <class T>
class Stack{
public:
Stack (int size){
top = -1;
MAX_SIZE = size;
v = new T (size);
}
~Stack(){ delete v;}
T pop();
void push (T);
class Underflow{};
class Overflow{};
private:
int top;
int MAX_SIZE;
T* v;
};
genericStackImpl.c++:
#include "genericStack.h"
template <class T>
void Stack <T> :: push (T c){
if (top == MAX_SIZE - 1) throw Overflow();
v[++top] = c;
}
template <class T>
T Stack <T> :: pop(){
if (top < 0) throw Underflow();
return v[top--];
}
driver.c++:
#include <iostream>
#include "genericStack.h"
int main(){
Stack<char> sc(3);
try{
while (true) sc.push ('p');
}
catch (Stack<char>::Overflow){std::cout << "Overflow caught\n";}
try{
while (true) std::cout << sc.pop() << '\n';
}
catch (Stack<char>::Underflow){ std::cout << "Underflow caught\n";}
return 0;
}
When i compile using g++ 4.5:
g++ -o driver driver.c++ genericStackImpl.c++
I get these errors:
/tmp/ccLXRXgF.o: In function `main':
driver.c++:(.text+0x2e): undefined reference to `Stack<char>::push(char)'
driver.c++:(.text+0x3c): undefined reference to `Stack<char>::pop()'
collect2: ld returned 1 exit status
I dont understand what the problem is. If i move the implementation in the driver file, then it compiles and runs.
Generally speaking, template definitions need to also be in the header file. An exception to this is when you are explicitly instantiating, or using explicit specialisations, neither of which you are doing.
One way to solve this would be to move the contents of genericStackImpl.c++ to the bottom of its header file.
The reason for this is because template functions are not actual functions, they are just templates. A template is used (instantiated) to create actual functions, and those are what you link against.
There are no functions in genericStackImpl.c++. The functions only get created once you use them, i.e. the first time the compiler sees sc.push and sc.pop. Unfortunately, when driver.c++ tries to create these functions, it can't find the template bodies -- they hidden in genericStackImpl.c++! Instead, it just compiles a reference to those functions, hoping that some other file will make them.
Finally, when it comes to link time, the linker can't find the function anywhere, so it gives you an error.
Another way to solve this would be to explicitly instantiate those functions yourself in genericStackImpl.c++, i.e.
template class Stack<char>;
This will create the functions, and the linker will find them.
The problem with this approach is that it require you to know what types your going to be using in your stack beforehand, so most people just put template definitions in the header file.
Related
I am Trying to explore partial specialization of templates in order to build a traits system. Unfortunately I cannot get the full thing working. I created the simplest model to show what does not work. It is not even clear to me whether I am trying something that is not supported (actually I see around examples of the same nature but the devil is in the details).
I am just creating a small example in which I have two enums and would like to create a string differently depending on the combination of the two. Of course this is just a dummy example to show the problem, the same thing in this case can be done in many other ways.
#ifndef TESTTRAITS_H_
#define TESTTRAITS_H_
#include <string>
using namespace std;
enum MovementType {
WALKS = 0, SWIMS = 1
};
enum AnimalType {
DOG = 0, CAT = 1, DOLPHIN = 2
};
template<AnimalType A, MovementType B>
struct movementAnimal {
static const string quality;
};
template<AnimalType A>
struct movementAnimal<A,WALKS> {
static const string quality;
};
template<AnimalType A>
struct movementAnimal<A,SWIMS> {
static const string quality;
};
#endif /* TESTTRAITS_H_ */
Now I write the assignment of the static variable
#include "TestTraits.h"
template<>
const string movementAnimal<DOLPHIN, WALKS>::quality = "Not capable";
template<>
const string movementAnimal<DOLPHIN, SWIMS>::quality = "Excellent";
template<AnimalType A>
const string movementAnimal<A, SWIMS>::quality = "Decent";
template<AnimalType A>
const string movementAnimal<A, WALKS>::quality = "Very Well";
And a small main function
#include <iostream>
using namespace std;
#include "TestTraits.h"
int main() {
cout << movementAnimal<DOLPHIN,WALKS>::quality << endl;
cout << movementAnimal<DOG,WALKS>::quality << endl;
return 0;
}
If I compile I get the error:
/src/TestProject.cpp:15: undefined reference to `movementAnimal<(AnimalType)0, (MovementType)0>::quality[abi:cxx11]'
collect2: error: ld returned 1 exit status>
If I remove the reference to movementAnimal<DOG,WALKS>::quality then it compiles perfectly.
I get that it is not digesting the partial template specification
template<AnimalType A>
const string movementAnimal<A, WALKS>::quality = "Very Well";
I do not know why and whether it is possible to have the pattern working.
As I can see, you put these definitions into separate files. The definition of the template classes is in TestTraits.h, but the definition of the static consts is somewhere else. The main CPP file includes just the TestTraits.h. That should sound like a good decision, but that doesn't work in the world of templates.
So, you have defined the enums and templates/partial specializations. Your main cpp module sees these definitions. Good. The compiler knows the template classes when it instantiates the walking dog here:
cout << movementAnimal<DOG,WALKS>::quality << endl;
Does the compiler see the definition of the static const? If it doesn't, the code like that is useless:
template<AnimalType A>
const string movementAnimal<A, WALKS>::quality = "Very Well";
When the compiler sees the code above it cannot know all the values of A that you would use. So whenever you decide that the DOG WALKS, this instantiation point shall see the definition of const string movementAnimal<A, WALKS>::quality;
The solution is to ensure that the code from main function knows both definitions of template classes and the definitions of static consts.
There are two solutions. First is to put everything into one header file or to include both files from cpp file. Don't forget to include both.
The second solution is to have an explicit instantiation of some classes somewhere in your code:
template class movementAnimal<DOG, WALKS>;
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 7 years ago.
I have no idea why this is happenning, since I think I have everything properly declared and defined.
I have the following program, designed with templates. It's a simple implementation of a queue, with the member functions "add", "substract" and "print".
I have defined the node for the queue in the fine "nodo_colaypila.h":
#ifndef NODO_COLAYPILA_H
#define NODO_COLAYPILA_H
#include <iostream>
template <class T> class cola;
template <class T> class nodo_colaypila
{
T elem;
nodo_colaypila<T>* sig;
friend class cola<T>;
public:
nodo_colaypila(T, nodo_colaypila<T>*);
};
Then the implementation in "nodo_colaypila.cpp"
#include "nodo_colaypila.h"
#include <iostream>
template <class T> nodo_colaypila<T>::nodo_colaypila(T a, nodo_colaypila<T>* siguiente = NULL)
{
elem = a;
sig = siguiente;//ctor
}
Afterwards, the definition and declaration of the queue template class and its functions:
"cola.h":
#ifndef COLA_H
#define COLA_H
#include "nodo_colaypila.h"
template <class T> class cola
{
nodo_colaypila<T>* ult, pri;
public:
cola<T>();
void anade(T&);
T saca();
void print() const;
virtual ~cola();
};
#endif // COLA_H
"cola.cpp":
#include "cola.h"
#include "nodo_colaypila.h"
#include <iostream>
using namespace std;
template <class T> cola<T>::cola()
{
pri = NULL;
ult = NULL;//ctor
}
template <class T> void cola<T>::anade(T& valor)
{
nodo_colaypila <T> * nuevo;
if (ult)
{
nuevo = new nodo_colaypila<T> (valor);
ult->sig = nuevo;
ult = nuevo;
}
if (!pri)
{
pri = nuevo;
}
}
template <class T> T cola<T>::saca()
{
nodo_colaypila <T> * aux;
T valor;
aux = pri;
if (!aux)
{
return 0;
}
pri = aux->sig;
valor = aux->elem;
delete aux;
if(!pri)
{
ult = NULL;
}
return valor;
}
template <class T> cola<T>::~cola()
{
while(pri)
{
saca();
}//dtor
}
template <class T> void cola<T>::print() const
{
nodo_colaypila <T> * aux;
aux = pri;
while(aux)
{
cout << aux->elem << endl;
aux = aux->sig;
}
}
Then, I have a program to test these functions as follows:
"main.cpp"
#include <iostream>
#include "cola.h"
#include "nodo_colaypila.h"
using namespace std;
int main()
{
float a, b, c;
string d, e, f;
cola<float> flo;
cola<string> str;
a = 3.14;
b = 2.71;
c = 6.02;
flo.anade(a);
flo.anade(b);
flo.anade(c);
flo.print();
cout << endl;
d = "John";
e = "Mark";
f = "Matthew";
str.anade(d);
str.anade(e);
str.anade(f);
cout << endl;
c = flo.saca();
cout << "First In First Out Float: " << c << endl;
cout << endl;
f = str.saca();
cout << "First In First Out String: " << f << endl;
cout << endl;
flo.print();
cout << endl;
str.print();
cout << "Hello world!" << endl;
return 0;
}
But when I build, the compiler throws errors in every instance of the template class:
undefined reference to `cola(float)::cola()'... (it's actually cola'<'float'>'::cola(), but this doesn't let me use it like that.)
And so on. Altogether, 17 warnings, counting the ones for the member functions being called in the program.
Why is this? Those functions and constructors WERE defined. I thought that the compiler could replace the "T" in the template with "float", "string" or whatever; that was the advantage of using templates.
I read somewhere here that I should put the declaration of each function in the header file for some reason. Is that right? And if so, why?
This is a common question in C++ programming. There are two valid answers to this. There are advantages and disadvantages to both answers and your choice will depend on context. The common answer is to put all the implementation in the header file, but there's another approach will will be suitable in some cases. The choice is yours.
The code in a template is merely a 'pattern' known to the compiler. The compiler won't compile the constructors cola<float>::cola(...) and cola<string>::cola(...) until it is forced to do so. And we must ensure that this compilation happens for the constructors at least once in the entire compilation process, or we will get the 'undefined reference' error. (This applies to the other methods of cola<T> also.)
Understanding the problem
The problem is caused by the fact that main.cpp and cola.cpp will be compiled separately first. In main.cpp, the compiler will implicitly instantiate the template classes cola<float> and cola<string> because those particular instantiations are used in main.cpp. The bad news is that the implementations of those member functions are not in main.cpp, nor in any header file included in main.cpp, and therefore the compiler can't include complete versions of those functions in main.o. When compiling cola.cpp, the compiler won't compile those instantiations either, because there are no implicit or explicit instantiations of cola<float> or cola<string>. Remember, when compiling cola.cpp, the compiler has no clue which instantiations will be needed; and we can't expect it to compile for every type in order to ensure this problem never happens! (cola<int>, cola<char>, cola<ostream>, cola< cola<int> > ... and so on ...)
The two answers are:
Tell the compiler, at the end of cola.cpp, which particular template classes will be required, forcing it to compile cola<float> and cola<string>.
Put the implementation of the member functions in a header file that will be included every time any other 'translation unit' (such as main.cpp) uses the template class.
Answer 1: Explicitly instantiate the template, and its member definitions
At the end of cola.cpp, you should add lines explicitly instantiating all the relevant templates, such as
template class cola<float>;
template class cola<string>;
and you add the following two lines at the end of nodo_colaypila.cpp:
template class nodo_colaypila<float>;
template class nodo_colaypila<std :: string>;
This will ensure that, when the compiler is compiling cola.cpp that it will explicitly compile all the code for the cola<float> and cola<string> classes. Similarly, nodo_colaypila.cpp contains the implementations of the nodo_colaypila<...> classes.
In this approach, you should ensure that all the of the implementation is placed into one .cpp file (i.e. one translation unit) and that the explicit instantation is placed after the definition of all the functions (i.e. at the end of the file).
Answer 2: Copy the code into the relevant header file
The common answer is to move all the code from the implementation files cola.cpp and nodo_colaypila.cpp into cola.h and nodo_colaypila.h. In the long run, this is more flexible as it means you can use extra instantiations (e.g. cola<char>) without any more work. But it could mean the same functions are compiled many times, once in each translation unit. This is not a big problem, as the linker will correctly ignore the duplicate implementations. But it might slow down the compilation a little.
Summary
The default answer, used by the STL for example and in most of the code that any of us will write, is to put all the implementations in the header files. But in a more private project, you will have more knowledge and control of which particular template classes will be instantiated. In fact, this 'bug' might be seen as a feature, as it stops users of your code from accidentally using instantiations you have not tested for or planned for ("I know this works for cola<float> and cola<string>, if you want to use something else, tell me first and will can verify it works before enabling it.").
Finally, there are three other minor typos in the code in your question:
You are missing an #endif at the end of nodo_colaypila.h
in cola.h nodo_colaypila<T>* ult, pri; should be nodo_colaypila<T> *ult, *pri; - both are pointers.
nodo_colaypila.cpp: The default parameter should be in the header file nodo_colaypila.h, not in this implementation file.
You will have to define the functions inside your header file.
You cannot separate definition of template functions in to the source file and declarations in to header file.
When a template is used in a way that triggers its intstantation, a compiler needs to see that particular templates definition. This is the reason templates are often defined in the header file in which they are declared.
Reference:
C++03 standard, ยง 14.7.2.4:
The definition of a non-exported function template, a non-exported member function template, or a non-exported member function or static data member of a class template shall be present in every translation unit in which it is explicitly instantiated.
EDIT:
To clarify the discussion on the comments:
Technically, there are three ways to get around this linking problem:
To move the definition to the .h file
Add explicit instantiations in the .cpp file.
#include the .cpp file defining the template at the .cpp file using the template.
Each of them have their pros and cons,
Moving the defintions to header files may increase the code size(modern day compilers can avoid this) but will increase the compilation time for sure.
Using the explicit instantiation approach is moving back on to traditional macro like approach.Another disadvantage is that it is necessary to know which template types are needed by the program. For a simple program this is easy but for complicated program this becomes difficult to determine in advance.
While including cpp files is confusing at the same time shares the problems of both above approaches.
I find first method the easiest to follow and implement and hence advocte using it.
This link explains where you're going wrong:
[35.12] Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?
Place the definition of your constructors, destructors methods and whatnot in your header file, and that will correct the problem.
This offers another solution:
How can I avoid linker errors with my template functions?
However this requires you to anticipate how your template will be used and, as a general solution, is counter-intuitive. It does solve the corner case though where you develop a template to be used by some internal mechanism, and you want to police the manner in which it is used.
Figuring if something wasn't broke, I'd break it, I decided to specialize a class I had so that it could be templated between float and double precision automagically.
I have the following [simplified] class declaration:
// Quatcam.h
#pragma once
#include <boost/math/quaternion.hpp>
#include <boost/numeric/ublas/matrix.hpp>
template<typename FloatType>
class QuaternionCamera
{
public:
QuaternionCamera();
void applyTranslation(boost::numeric::ublas::vector<FloatType> translationVector);
boost::numeric::ublas::matrix<FloatType> getTranslationMatrix();
protected:
boost::numeric::ublas::vector<FloatType> m_location;
boost::math::quaternion<FloatType> m_orientation;
};
I have defined the member functions in a .cpp file:
//Quatcam.cpp
#include "Quatcam.h"
using namespace boost::numeric::ublas;
template<typename FloatType>
QuaternionCamera<FloatType>::QuaternionCamera()
: m_location(3),
m_orientation(1,0,0,0)
{
m_location[0] = m_location[1] = m_location[2] = 0;
}
template<typename FloatType>
void QuaternionCamera<FloatType>::applyTranslation(boost::numeric::ublas::vector<FloatType> translationVector)
{
m_location += translationVector;
}
template<typename FloatType>
boost::numeric::ublas::matrix<FloatType> QuaternionCamera<FloatType>::getTranslationMatrix()
{
boost::numeric::ublas::matrix<FloatType> returnMatrix = boost::numeric::ublas::identity_matrix<FloatType>(4,4);
boost::numeric::ublas::vector<FloatType> invTrans = -m_location;
returnMatrix(3,0) = invTrans[0];
returnMatrix(3,1) = invTrans[1];
returnMatrix(3,2) = invTrans[2];
return returnMatrix;
}
This code by itself will happily compile into a .lib or .obj file, but attempting to use the class in situ results in linker errors. Here is my example main.cpp attempting to use the class:
#include "Quatcam.h"
#include <boost/numeric/ublas/io.hpp>
#include <iostream>
int main(int argc, char** argv)
{
QuaternionCamera<float> qcam;
boost::numeric::ublas::vector<float> loc(3);
loc[0] = 0;
loc[1] = 5;
loc[2] = 0;
qcam.applyTranslation(loc);
boost::numeric::ublas::matrix<float> qtm = qcam.getTranslationMatrix();
std::cout << "qtm: "<< qtm << std::endl;
return 0;
}
This code fails to link with an error for missing symbols for getTranslationMatrix and applyTranslation. I assume this is because I haven't technically specified a full specialization of the functions for the type float.
Question(s)
Given that the behavior is the same for any atomic input type (float, double, even int, etc...) and only affects the precision of the answers.
Is there a way to force the compiler to emit specializations for all of them without having to;
move all of the function definitions into the header file, or;
explicitly create specializations for all data types that would presumably involve a lot of copypasta?
Recommended links
Why can templates only be implemented in the header file?
Why do C++ template definitions need to be in the header?
Recommended Practice
Instead of moving the definitions from the .cpp to the header, rename the .cpp to .tpp and add #include "Quatcam.tpp" at the end of Quatcam.h.
This is how you typically split up the template declarations, and their definitions, while still having the definitions available for instantiation.
Note: If you follow this road, you should not compile the .tpp by itself, as you were doing with the .cpp.
Explicit Instantiation
You can explicitly instantiate the templates in question in your .cpp to provide them for the linker, but that requires that you know the exact types that you'd require an instantation of.
This means that if you only explicitly instantiate QuaternionCamera<float>, you'd still get a linker error if main.cpp tries to use QuaternionCamera<double>.
There's no way of forcing instantiation of all "atomic input types", you'll have to write them all out explicitly.
template class QuaternionCamera<float>; // explicit instantiation
template class QuaternionCamera<double>; // etc, etc...
You should put these functions into the header file, not into the .cpp source.
The compiler only creates function instantiations after the template argument deduction is complete. The resulting object file will contain a compiled function for each type that the template was used with.
However, .cpp files are compiled separately. So, when you compile Quatcam.cpp, the compiler doesn't find any instantiations for this type, and doesn't create a function body. This is why you end up with a linker error.
To put it simply, this is how your header should look like:
template<typename T>
class Foo {
void Print();
T data;
};
// If template arguments are specified, function body goes to .cpp
template<>
void Foo<float>::Print();
// Template arguments are incomplete, function body should remain in the header
template<typename T>
void Foo<T>::Print() {
std::cout << data;
}
And this should to the .cpp source:
template<>
void Foo<float>::Print() {
std::cout << floor(data);
}
I want to overload new operator in a template class. But something wrong happends.
In file test4.h, I defined a class
#include <stddef.h>
#include <iostream>
template <class T>
class lei{
public:
T me;
static void* operator new(size_t size);
};
test4.cpp implement the new operator.
#include "test4.h"
template <class T>
void* lei<T>::operator new(size_t size){
std::cout << size << std::endl;
}
main.cpp
#include "test4.h"
int main(){
lei<size_t> *pl;
pl = new lei<size_t>;
}
I compile the cpp files to .o file. Everything is OK.
But when I link them to the executable file, error occurs:
main.o: In function `main':
main.c:(.text+0x19): undefined reference to `lei<unsigned int>::operator new(unsigned int)'
collect2: ld returned 1 exit status
but everything is OK, if I don't use template.Why that happens?
So, I hope someone can help me.
You need to put the template implementation in the header file also. The implementation needs to be visible to the compiler when it needs to instantiate the template.
This the C++FAQ 35.12 to learn why this is necessary, and the following entries for ways to fix it.
(Also, your implementation of operator new should return something, it should not compile otherwise.)
Move the implementation of the operator to the header file, and it should compile.
The implementation of your new operator needs to be in the header file as well, not the .cpp file.
Been away from C++ for a few years and am getting a linker error from the following code:
Gene.h
#ifndef GENE_H_INCLUDED
#define GENE_H_INCLUDED
template <typename T>
class Gene {
public:
T getValue();
void setValue(T value);
void setRange(T min, T max);
private:
T value;
T minValue;
T maxValue;
};
#endif // GENE_H_INCLUDED
Gene.cpp
#include "Gene.h"
template <typename T>
T Gene<T>::getValue() {
return this->value;
}
template <typename T>
void Gene<T>::setValue(T value) {
if(value >= this->minValue && value <= this->minValue) {
this->value = value;
}
}
template <typename T>
void Gene<T>::setRange(T min, T max) {
this->minValue = min;
this->maxValue = max;
}
Using Code::Blocks and GCC if it matters to anyone. Also, clearly porting some GA stuff to C++ for fun and practice.
The template definition (the cpp file in your code) has to be included prior to instantiating a given template class, so you either have to include function definitions in the header, or #include the cpp file prior to using the class (or do explicit instantiations if you have a limited number of them).
Including the cpp file containing the implementations of the template class functions works. However, IMHO, this is weird and awkward. There must surely be a slicker way of doing this?
If you have only a few different instances to create, and know them beforehand, then you can use "explicit instantiation"
This works something like this:
At the top of gene.cpp add the following lines
template class Gene<int>;
template class Gene<float>;
In if(value >= this->minValue && value <= this->minValue) the second minValue should be maxValue, no?
Echo what Sean said: What's the error message? You've defined and declared the functions, but you've not used them in anything anywhere, nor do I see an error (besides the typo).
TLDR
It seems that you need an Explicit Instantiation i.e. to actually create the class. Since template classes are just "instructions" on how to create a class you actually need to tell the compiler to create the class. Otherwise the linker won't find anything when it goes looking.
The thorough explanation
When compiling your code g++ goes through a number of steps the problem you're seeing occurs in the Linking step. Template classes define how classes "should" be created, they're literally templates. During compile time g++ compiles each cpp file individually so the compiler sees your template on how to create a class but no instructions on what "classes" to create. Therefore ignores it. Later during the linking step the g++ attempts to link the file containing the class (the one that doesn't exist) and fails to find it ultimately returning an error.
To remedy this you actually need to "explicitly instantiate" the class by adding the following lines to Gene.cpp after the definition of the class
template class Gene<whatever_type_u_wanna_use_t>;int
Check out these docs I found them to be super helpful.