PDA

View Full Version : C++ template class -- won't compile


tech419
12-27-2009, 06:39 PM
Hey

I'm writing a two-dimensional linked list for the purposes of matrix math. I am being hung up on something completely ridiculous, though.

I am making this a template class, so that, as a container, it can be more useful than just math. But the for some reason my compiler isn't liking my code. For the purposes of debugging, I reduced the class to just a single public method that prints the word "Hi!" to the command line, while leaving the template keywords in place. The code (in three source files is as follows):

//linkedmatrix.h

#include <iostream>

using namespace std;

template <class type> class LinkedMatrixRef {
public:

void printHi(void);

};

//linkedmatrix.cpp

#include "linkedmatrix.h"

using namespace std;

template <class type> void LinkedMatrixRef<type>::printHi(){

cout<<"Hi!"<<endl;

}

//main.cpp

#include "linkedmatrix.h"

using namespace std;

int main (int argc, char * const argv[]){

LinkedMatrixRef <float>l;

l.printHi();

return 0;

}

The error I receive is as follows:

Undefined symbols:
"LinkedMatrixRef<float>::printHi()", referenced from:
_main in main.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

As far as I know, I have declared everything correctly, and when I remove the template aspect of the class, it compiles and runs correctly.

Any help is greatly appreciated.

EDIT: If all the code is condensed to one source file, the code compiles and runs perfectly.

oracleguy
12-27-2009, 08:24 PM
EDIT: If all the code is condensed to one source file, the code compiles and runs perfectly.

What compiler are you using? I forget why, but there is a reason why it has to be in one file. We've talked about it on this forum before but a quick search didn't find the post I was looking for.

tech419
12-27-2009, 08:29 PM
I am using GCC 4.something, but I am also compiling through x-code.

Do I need the class implementation to be in the same source file as the place where I call the method, or can I just condense the class to the header file? Is there a workaround for this?

sage45
12-27-2009, 09:35 PM
To answer your immediate question, yes, you can take your .h and .cpp files for the LinkedMatrix Class and condense them into one single class file.

To answer your initial question and to provide a condensed explanation for the reason behind your compile problem.

From the point of view of the compiler, templates are not normal functions or classes. They are compiled on demand, meaning that the code of a template function is not compiled until an instantiation with specific template arguments is required. At that moment, when an instantiation is required, the compiler generates a function specifically for those arguments from the template.

When projects grow it is usual to split the code of a program in different source code files. In these cases, the interface and implementation are generally separated. Taking a library of functions as example, the interface generally consists of declarations of the prototypes of all the functions that can be called. These are generally declared in a "header file" with a .h extension, and the implementation (the definition of these functions) is in an independent file with c++ code.

Because templates are compiled when required, this forces a restriction for multi-file projects: the implementation (definition) of a template class or function must be in the same file as its declaration. That means that we cannot separate the interface in a separate header file, and that we must include both interface and implementation in any file that uses the templates.

Since no code is generated until a template is instantiated when required, compilers are prepared to allow the inclusion more than once of the same template file with both declarations and definitions in a project without generating linkage errors.

HTH,

-saige-

tech419
12-27-2009, 09:39 PM
Alright, I consolidated everything into linkedmatrix.h, and now it compiles and runs perfectly. Thanks for all your help.

anonymouscodder
01-02-2010, 08:00 PM
C++0x introduces the extern template feature, that is not supported by today C++ standard.

But GCC supports the extern template feature, as you can see here: http://gcc.gnu.org/projects/cxx0x.html.

//linkedmatrix.cpp

#include "linkedmatrix.h"

using namespace std;

extern template <class type> void LinkedMatrixRef<type>::printHi(){

cout<<"Hi!"<<endl;

}

Now your code should work.

You can understand better the extern template idea checking this link: http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=344.

sharjith
02-10-2010, 10:40 PM
It is not possible to write the implementation of a template class in a seperate cpp file and compile. All the ways to do so, if anyone claims, are workarounds to mimic the usage of seperate cpp file but practically if you intend to write a template class library and distribute it with header and lib files to hide the implementation, it is simply not possible.

To know why, let us look at the compilation process. The header files are never compiled. They are only preprocessed. The preprocessed code is then clubbed with the cpp file which is actually compiled. Now if the compiler has to generate the appropriate memory layout for the object it needs to know the data type of the template class.

Actually it must be understood that template class is not a class at all but a template for a class the declaration and definition of which is generated by the compiler at compile time after getting the information of the data type from the argument. As long as the memory layout cannot be created, the insrtuctions for the method definition cannot be generated. Remember the first argument of the class method is the 'this' operator. All class methods are converted into individual methods with name mangling and the first parameter as the object which it operates on. The 'this' argument is which actually tells about size of the object which incase of template class is unavailable for the compiler unless the user instantiates the object with a valid type argument. In this case if you put the method definitions in a seperate cpp file and try to compile it the object file itself will not be generated with the class information. The compilation will not fail, it would generate the object file but it won't generate any code for the template class in the object file. This is the reason why the linker is unable to find the symbols in the object files and the build fails.

Now what is the alternative to hide important implementation details? As we all know the main objective beind seperating interface from implementation is hiding implementation details in binary form. This is where you must seperate the datastructures and algorithms. Your template classes must represent only datastructures not the algorithms. This enables you to hide more valuable implementation details in seperate non-templatized class libraries, the classes inside which would work on the template classes or just use them to hold data. The template class would actually contain less code to assign, get and set data. Rest of the work would be done by the algorithm classes.

I hope this discussion would be helpful.