While making a template linked list, rather than having the files list.h and list.cpp, we create list.h and list.cpp.h. The .cpp.h file contains the implementation for the linked list class. At the end of list.h, before the #ENDIF, we #include "list.cpp.h".
I understand that by making the .cpp file a header file we are able to avoid compiling it, but how does this work? We have needed to compile implementations that rely on using "template < class T >" in the past, so why do we not have to compile this implementation file?
Edit: My question was marked as a duplicate with a link to Why can templates only be implemented in the header file? , which I had already read. That question does not answer why the template implementation does not need to be compiled like a normal .cpp implementation file does. If we can avoid compiling implementations by making them header files, why do we not do that for every implementation? What are the downsides?
Does instantiating a template compile the code for each instance of that template? If my .cpp ever requires the use of a template in one of its functions, then why wouldn't I change it to a header file if it avoids this initial compilation?
I hope my question makes more sense.
Remember, a #include directive just pulls the contents of the header into the file that's currently being compiled. So the template does get compiled; it gets compiled in every translation unit that #includes the file where the template is defined. And when the template is used (later in that file) it gets instantiated.
In what you are saying, you are including the templates as header file, since your .h file includes the .ccp.h file in the end.
So this is a convention on your project, to seperate the normal .h and the template code in two files.
Hence the template code, in your case, is compiled into the regular .cpp code.
The reason why you would want to avoid that is "bloat" -- every .cpp file will create it's own copy of the template code used in that cpp-unit, so if if A.cpp and B.cpp both includes T.cpp.h, they may both create the same code if they use the same templates, and it takes a smart optimizer to remove all the duplication.
I'm currently writing a logger for my C++ project (I need it to have near to no dependences, so I don't want to take a prewritten one). It contains this function:
template <typename T>
Logger& Logger::operator<<(T f) {
m_file<<f;
return *this;
}
The logger.cpp code compiles, but when I call the log functions in my main.cpp, I have this compiler error:
/home/tuxer/prog/cpp/PRay/server/src/main.cpp:110: undefined reference to `Logger& Logger::operator<< <int>(int)'
for this line of code :
log<<lul; (lul being a int variable equals to 2)
The logger.o file is correctly included, as the Logger::init() function works properly and doesn't raise any linking error.
Thanks :)
Since you have non-inline templates, you need to force instantiation. See for example How do I force a particular instance of a C++ template to instantiate?.
The simple thing to do is to put the Logger::operator<< template in the header file. The compiler will automatically instantiate the versions it needs, and the linker will remove the duplicates (well, at least the ones that weren't inlined).
You shouldn't need to force instantiation unless your linker is old (e.g. gcc 2.7 or earlier).
This is the general rule with template code: put the definitions in the header file unless you have a good reason not to.
See Why can templates only be implemented in the header file? as well.
I have a program were I was given the compiled .o file but I do not have the original .cc file and also I only have a half-way finished header file. The header file has all the method signatures but is lacking the private variable declarations. I am trying to get this .o file to work with the project but get a segmentation fault at the constructor of the class defined by the .o file. The program compiles. How do I get this to work? The program is a homework assignment and the teacher does not want us to see the .cc file. Also my teacher knows about the issue. I am just trying to figure it out on my own (and hopefully with the help of you guys :) ). I thought I had done this before a while ago with another teacher but did not have any problems. There is a makefile that is used to compile the program.
If you are using a C++ program, and the header file includes class definitions, the class definitions must exactly match those that were used to originally build the file. This is the One Definition Rule. If your professor has removed private variable declarations from the class definitions, you will likely end up with crashes; this is because your different .o files will disagree about the size of the objects defined by those classes.
If your professor wants to hide the implementation of the class, they should use the p/impl pattern. If you want to use the header file, you must remove the mangled class definitions entirely and not attempt to use them (you can use a forward definition as in class Foo; to satisfy any functions which take/return the class as a pointer parameter, however).
I currently have a program where my main code is in a file main.cpp.
Main.cpp includes a header file "class.h" that declares a class that is used within main.cpp.
Also in main.cpp I have function declarations that declare the functions I use within main.cpp.
The code for these functions is in a separate .cpp file fucntions.cpp.
Like main.cpp, functions.cpp also includes class.h as the class type is used within the functions.
class.h contains the class declaration only.
The implementation code for class.h is in a separate .cpp file classimplementation.cpp.
It all works fine until I try to make the class in class.h a template class.
Then I get linking problems. Research and testing has shown me that this is because the definition of the template class functions needs to reside in class.h with the declaration.
I therefore took the required code out of classimplementations.cpp and put it into class.h.
This did solve my original linking issues but instead I get more linking errors that seem to be telling me I am trying to redefine the functions that I moved to into class.h.
This I think is because class.h is being called by main.cpp and again by functions.cpp.
Therefore the functions in class.h are being defined twice:
Error 41 error LNK2005: "public: __thiscall RecordPocket::RecordPocket(int)" (??0?$RecordPocket#VT####QAE#H#Z) already defined in classimplementation.obj functions.obj
I know that class implementation code should really be kept out of include files but due to the template class limitation of having to keep the class functions local I appear (in my novice mind) to have no choice.
Has anyone been in this scenario and can offer any advice.
I have tried surrounding the functions I moved from classimplementation.cpp to class.h with the standard ifndef CLASSIMP, #define CLASSIMP code and PRAGMA ONCE but neither make any difference.
If all else fails I will move the functions from functions.cpp into main.cpp so that class.h gets called just the once but I’d rather find out what I’m doing wrong as I’m sure it will happen again.
You could keep the template functions inside the template<> class what{/HERE/};
template<typename T>
class MyTempClass{
void myFunctions{
// code here
}
}
EDITED: I removed the code corrected by Glen
I think your problem is revolves around these issues. As you have implied any template function definition (i.e. template function of member function of a template class) needs to be fully expressed in the .h file because when the compiler finds a specific instance of the template it needs to build the function.
You figured this out and moved some implementation into your class.h file. Now if the linker find a MyFunction() in more than one module then is just discards one of them a no linker error is reported.
However you can't define the same non-template function in two different modules as this generates the error you are getting above. So I suspect you also moved some non-template functionality into the .h file; thus including it in two separate obj files and generating the linker error. This theory is support by your quoted error message as I note __thiscall RecordPocket::RecordPocket(int) does not appear to be template.
I'm getting linkage errors of the following type:
Festival.obj : error LNK2019:
unresolved external symbol "public:
void __thiscall Tree::add(class Price &)"
(?add#?$Tree#VPrice####QAEXAAVPrice###Z)
referenced in function
__catch$?AddBand#Festival##QAE?AW4StatusType##HHH#Z$0
I used to think it has to do with try-catch mechanism, but since been told otherwise. This is an updated version of the question.
I'm using Visual Studio 2008, but I have similar problems in g++.
The relevant code:
In Festival.cpp
#include "Tree.h"
#include <exception>
using namespace std;
class Band{
public:
Band(int bandID, int price, int votes=0): bandID(bandID), price(price), votes(votes){};
...
private:
...
};
class Festival{
public:
Festival(int budget): budget(budget), minPrice(0), maxNeededBudget(0), priceOffset(0), bandCounter(0){};
~Festival();
StatusType AddBand(int bandID, int price, int votes=0);
...
private:
Tree<Band> bandTree;
...
};
StatusType Festival::AddBand(int bandID, int price, int votes){
if ((price<0)||(bandID<0)){
return INVALID_INPUT;
}
Band* newBand=NULL;
try{
newBand=new Band(bandID,price-priceOffset,votes);
}
catch(bad_alloc&){return ALLOCATION_ERROR;}
if (bandTree.find(*newBand)!=NULL){
delete newBand;
return FAILURE;
}
bandTree.add(*newBand);
....
}
In Tree.h:
template<class T>
class Tree{
public:
Tree(T* initialData=NULL, Tree<T>* initialFather=NULL);
void add(T& newData);
....
private:
....
};
Interestingly enough I do not have linkage errors when I try to use Tree functions when type T is a primitive type like an int.
Is there Tree.cpp? If there is, maybe you forgot to link it? Where is the implementation of Tree::add?
In addition I don't see where you call Tree::add. I guess it should be inside the try statement, right after the new?
Just a reminder:
For most compilers (i.e. those that practice separate compilation) the implementation of the member functions of a template class has to be visible during the compilation of the source file that uses the template class. Usually people follow this rule by putting the implementation of the member functions inside the header file.
Maybe Tree::add isn't inside the header? Then a possible solution in the discussed case will be to put Tree::add implementation inside the header file.
The difference between regular classes and template classes exists because template classes are not "real" classes - it is, well, a template. If you had defined your Tree class as a regular class, the compiler could have used your code right away. In case of a template the compiler first "writes" for you the real class, substituting the template parameters with the types you supplied. Now, compiler compiles cpp files one by one. He is not aware of other cpp files and can use nothing from other cpp files. Let's say your implementation of Tree:add looks like this:
void Tree::add(T& newData)
{
newData.destroyEverything();
}
It is totally legitimate as long as your T has method destroyEverything. When the compiler compiles Class.cpp it wants to be sure that you don't do with T anything it doesn't know. For example Tree<int> won't work because int doesn't have destroyEverything. The compiler will try to write your code with int instead of T and find out that the code doesn't compile. But since the compiler "sees" only the current cpp and everything it includes, it won't be able to validate add function, since it is in a separate cpp.
There won't be any problem with
void Tree::add(int& newData)
{
newData.destroyEverything();
}
implemented in a separate cpp because the compiler knows that int is the only acceptable type and can "count on himself" that when he gets to compile Tree.cpp he will find the error.
Are you sure the try/catch has anything to do with it? What happens if you simply comment out the try and catch lines, leave the rest of the code as it is, and build that?
It might just be that you're missing the library that defines Tree::add(class Price &) from your link line.
Update: using Tree functions with a primitive type doesn't result in a linking error.
I updated my question in light of some of the things that were said.
As others have stated you need to show the implementation of Treee::add() and tell us how you are linking it.
On an unrelated point, if you are using constructs like:
Band* newBand=NULL;
try{
newBand=new Band(bandID,price-priceOffset,votes);
}
catch(bad_alloc&){return ALLOCATION_ERROR;}
throughout your code, you are frankly wasting your time. The chances of you getting to a point of memory exhaustion in a modern OS are remote and the chances of you doing anything useful after it has happened are roughly zero. You will be much better off simply saying:
Band * newBand = new Band ( bandID, price - priceOffset, votes );
ot possibly:
Band newBand( bandID, price - priceOffset, votes );
and forgetting the exception handling in this case.
You wrote in a comment:
I considered this but the function is part of Tree.h, and I do include it. The function defined is: template void Tree::add(T& newData); We call it the following way: priceTree.add(*newPriceNode); whereas priceTree is Tree, both of which are defined in the cpp file in question.
instead of:
priceTree.add(*newPriceNode);
try:
priceTree.add(newPriceNode); //no "*" before "newPriceNode"
add() takes a reference to a node, not a pointer to a node (according to your definition of Tree).
You're getting linkage errors, not compiler errors. This tells us that the compiler knew what sort of function Tree::add() is, but didn't have a definition. In Tree.h, I see a declaration of the add() function, but not a definition. It looks odd to me; does anybody know where Tree.h came from?
Usually a template class comes with member function definitions in the include file, since the functions have to be instantiated somewhere, and the simplest thing is for the compiler to instantiate when used and let the linker sort it out. If the definitions are in Tree.h, I'd expect everything to work as planned.
So, I'm going to go out on a limb and suggest that the definitions are in a separate file, not linked in, and that there are provisions elsewhere for instantiating for basic types like Tree<int>. This is presumably to streamline compilation, as normally these things are compiled in multiple places, and that takes time.
What you need to do in that case is to find where Tree<int> is instantiated, and add an instantiation for your class.
I could be way off base here, but my explanation does fit the facts you've given.
Edit after first comments:
Templates are somewhat trickier than ordinary functions, which usually isn't a real problem. If the definitions for all the calls were in Tree.h, then Festival.cpp would be able to instantiate Tree<Band> and everything would be cool. That's the usual technique, and you're running into this problem because you're not using it.
When you write a function, it gets compiled, and the linker will find it. Any routine calling that function needs to know the function prototype, so it will know how to call it. When you write a template, you're not writing anything that will go directly into the program, but any use of the template counts as writing all the functions.
Therefore, there has to be some use of Tree<Band> somewhere in your program, for there to be a Tree<Band>::add() function compiled. The definition of Tree<T>::add has to be available to the compiler when Tree<Band> is instantiated, because otherwise the compiler has no idea what to compile. In this case, it's generating the function call, confident that you'll make sure the function is compiled elsewhere.
Therefore, you have to instantiate Tree<Band> inside a file that has access to both the definitions for Tree<T> and Band. This probably means a file that is, or includes, Tree.cpp and includes Festival.h.
The linker is already using Tree.cpp, but Tree.cpp doesn't have Tree<Band> defined in it, so it's meaningless to the linker. Templates are only useful for the compiler, and the linker only operates on what the compiler generated from templates.
The quick way to solve this is to take the definitions from Tree.cpp and put them in Tree.h. That will be likely to increase compilation and link times, unfortunately. The other technique is to instantiate all template uses in Tree.cpp, so that they'll be compiled there.