Separation of C ++ template classes into .hpp / .cpp files - is this possible?

I get errors trying to compile the C ++ template class, which is split between the .hpp and .cpp file:

 $ g++ -c -o main.o main.cpp $ g++ -c -o stack.o stack.cpp $ g++ -o main main.o stack.o main.o: In function `main': main.cpp:(.text+0xe): undefined reference to 'stack<int>::stack()' main.cpp:(.text+0x1c): undefined reference to 'stack<int>::~stack()' collect2: ld returned 1 exit status make: *** [program] Error 1 

Here is my code:

stack.hpp

 #ifndef _STACK_HPP #define _STACK_HPP template <typename Type> class stack { public: stack(); ~stack(); }; #endif 

stack.cpp

 #include <iostream> #include "stack.hpp" template <typename Type> stack<Type>::stack() { std::cerr << "Hello, stack " << this << "!" << std::endl; } template <typename Type> stack<Type>::~stack() { std::cerr << "Goodbye, stack " << this << "." << std::endl; } 

main.cpp

 #include "stack.hpp" int main() { stack<int> s; return 0; } 

ld , of course, correct: characters are not in stack.o .

The answer to this question does not help, as I already do, as they say.
This file may help, but I do not want to move each method to a .hpp file - I do not need to, should I?

Is the only reasonable solution to move the entire .cpp file to a .hpp file and just include everything, and not be referenced as a separate object file? It seems terribly ugly! In this case, I could also go back to my previous state and rename stack.cpp to stack.hpp and do with it.

+72
c ++ class linker header templates
Nov 12 '09 at 17:40
source share
16 answers

It is not possible to write an implementation of a template class in a separate cpp file and compile. All ways to do this, if anyone claims to, are workarounds that mimic the use of a separate cpp file, but in practice, if you intend to write a template class library and distribute it using header and lib files to hide the implementation, this is simply not possible.

To find out why, let's take a look at the compilation process. Header files are never compiled. They are only pre-processed. Then the pre-processed code is grouped with the cpp file, which is actually compiled. Now, if the compiler needs to create the appropriate memory layout for the object, it needs to know the data type of the template class.

In fact, it should be understood that the template class is not a class at all, but a template for a class whose declaration and definition is generated by the compiler at compile time after receiving information about the data type from the argument. Until a memory layout can be created, instructions for defining a method cannot be generated. Remember that the first argument to a class method is the 'this' operator. All methods of the class are converted to separate methods with the name mangling and the first parameter as the object on which it works. The argument to 'this', which actually indicates the size of the object that closes the template class, is not accessible to the compiler unless the user creates an object with a valid type argument. In this case, if you put the method definitions in a separate cpp file and try to compile it, the file object itself will not be generated with class information. Compilation will not fail, it will generate an object file, but it will not generate code for the template class in the object file. It is for this reason that the linker cannot find characters in object files, and the assembly failed.

Now, what is the alternative to hide important implementation details? As we all know, the main goal of separating the interface from the implementation is to hide the implementation details in binary form. Here you must separate data structures and algorithms. Your template classes should only represent data structures, not algorithms. This allows you to hide more important implementation details in separate class libraries without templates, classes within which template classes will work, or simply use them to store data. The template class will actually contain less code for assigning, receiving, and setting data. The rest of the work will be done by classes of algorithms.

I hope this discussion is helpful.

+129
Jan 26 '10 at 23:52
source share

This is possible if you know which instances you will need.

Add the following code at the end of stack.cpp and it will work:

 template class stack<int>; 

All non-table stack methods will be created, and the binding step will work fine.

+74
Nov 12 '09 at 19:13
source share

You can do it this way

 // xyz.h #ifndef _XYZ_ #define _XYZ_ template <typename XYZTYPE> class XYZ { //Class members declaration }; #include "xyz.cpp" #endif //xyz.cpp #ifdef _XYZ_ //Class definition goes here #endif 

This was discussed at Daniweb

Also in the FAQ , but using the C ++ export keyword.

+8
Apr 03 2018-12-12T00:
source share

No, It is Immpossible. Not without the export keyword, which for all purposes and purposes does not really exist.

The best you can do is put the implementation of your function in a .tcc or .tpp file and # include the .tcc file at the end of your .hpp file. However, this is just cosmetics; it still matches the implementation of everything in the header files. This is just the price you pay for using templates.

+6
Nov 12 '09 at 17:41
source share

I believe that there are two main reasons for splitting the boilerplate code into a header and cpp:

One for simple elegance. We all like to write code that wasy to read, manage and reuse later.

Another is the reduction in compilation time.

I currently (as always) have coding modeling software in conjunction with OpenCL, and we like to save the code, so it can be run using the types float (cl_float) or double (cl_double) as needed depending on the capabilities of HW. Now this is done using #define REAL at the beginning of the code, but it is not very elegant. Changing the desired accuracy requires recompiling the application. Since there are no real types of runtimes, we need to live with this for the time being. Fortunately, OpenCL kernels are compiled at runtime, and simple sizeof (REAL) allows us to adjust the runtime of the kernel code accordingly.

A much bigger problem is that even though the application is modular, there should also be patterns when developing helper classes (such as those that pre-compute simulation constants). These classes appear at least once at the top of the class dependency tree, since the final Simulation template will have an instance of one of these factory classes, which means that almost every time I make a small change to the factory of the class, all the software is needed rebuild. This is very annoying, but I cannot find a better solution.

+3
Nov 09 '12 at 9:05
source share

It is sometimes possible that most of the implementation is hidden in the cpp file, if you can extract the general functionality of foo all the template parameters into a class without a template (possibly type-unsafe). Then the header will contain the redirect calls of this class. A similar approach is used to combat the problem of "inflating the pattern."

+2
Nov 12 '09 at 18:07
source share

The problem is that the template does not generate the actual class, it is just a template telling the compiler how to create the class. You need to create a specific class.

A simple and natural way is to use the methods in the header file. But there is another way.

In your .cpp file, if you have a link to each instance and the template method that you need, the compiler will generate them there for use in your entire project.

new stack.cpp file:

 #include <iostream> #include "stack.hpp" template <typename Type> stack<Type>::stack() { std::cerr << "Hello, stack " << this << "!" << std::endl; } template <typename Type> stack<Type>::~stack() { std::cerr << "Goodbye, stack " << this << "." << std::endl; } static void DummyFunc() { static stack<int> stack_int; // generates the constructor and destructor code // ... any other method invocations need to go here to produce the method code } 
+2
Nov 12 '09 at 18:11
source share

If you know what types your stack will be used with, you can create an instance of them in the cpp file and save all the relevant codes there.

It is also possible to export them through DLLs (!), But it is rather difficult to get the syntax on the right (MS-specific combinations __declspec (dllexport) and the export keyword).

We used this in the math / geom library, which was built using the double / float pattern, but had quite a bit of code. (At that time I was looking for her for this, today I do not have this code.)

+2
Nov 12 '09 at 18:16
source share

Only if you #include "stack.cpp at the end of stack.hpp . I would recommend this approach only if the implementation was relatively large and if you renamed the .cpp file to a different extension to distinguish it from regular code.

+1
Nov 12 '09 at 17:46
source share

This is a pretty old question, but I think it’s interesting to see Arthur O'Dwyer’s presentation at cppcon 2016 . Good explanation, many subjects that should be considered should look.

+1
Jul 09 '17 at 10:29
source share

Since templates are compiled when necessary, this limits multifactor projects: the implementation (definition) of a class or function of a template must be in the same file as its declaration. This means that we cannot separate the interface in a separate header file and that we must include both the interface and the implementation in any file that uses templates.

0
Nov 12 '09 at 17:43
source share

You need to have everything in the hpp file. The problem is that the classes are not actually created until the compiler sees that they are needed for some OTHER cpp file, so it must have all the code to compile the template at that moment.

One thing I'm trying to do is try to split my templates into a common non-templated part (which can be split between cpp / hpp) and a part of the template for a specific type that inherits from a non-templated class.

0
Nov 12 '09 at 17:44
source share

Another possibility is to do something like:

 #ifndef _STACK_HPP #define _STACK_HPP template <typename Type> class stack { public: stack(); ~stack(); }; #include "stack.cpp" // Note the include. The inclusion // of stack.h in stack.cpp must be // removed to avoid a circular include. #endif 

I don't like this style proposal, but it might suit you.

0
Nov 12 '09 at 17:49
source share

The 'export' keyword is a way to separate a template implementation from a template declaration. This was introduced in the C ++ standard without an existing implementation. At one time, only a few compilers actually implemented it. Read the detailed information at the Report IT export article.

0
Nov 12 '09 at 17:51
source share

1) Remember that the main reason for separating .h and .cpp files is to hide the implementation of the class as compiled Obj code, which can be associated with user code that includes the .h class.

2) Classes without templates have all the variables that are specifically and specifically defined in the .h and .cpp files. Thus, the compiler will have information about all types of data used in the class before compiling / translating  generating an object / machine code. Template classes do not have information about a specific data type before the class user creates an object that transfers the required data type:

  TClass<int> myObj; 

3) Only after this instance does the compiler generate a specific version of the template class in accordance with the transferred data types.

4) Therefore .cpp CANNOT be compiled separately, not knowing the type of data specific to users. Therefore, it should remain the source code inside ".h" until the user specifies the required data type, then it can be generated for a specific data type, and then compiled

0
Apr 27 '14 at 18:39
source share

I am working with Visual Studio 2010, if you want to split your files into .h and .cpp, include the cpp header at the end of the .h file

-3
Jun 26 '13 at 14:00
source share