111

I am getting errors trying to compile a C++ template class which is split between a .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 is of course correct: the symbols aren't in stack.o.

The answer to this question does not help, as I'm already doing as it says.
This one might help, but I don't want to move every single method into the .hpp file—I shouldn't have to, should I?

Is the only reasonable solution to move everything in the .cpp file to the .hpp file, and simply include everything, rather than link in as a standalone object file? That seems awfully ugly! In that case, I might as well revert to my previous state and rename stack.cpp to stack.hpp and be done with it.

Community
  • 1
  • 1
exscape
  • 2,185
  • 4
  • 21
  • 25
  • There's two great workarounds for when you want to really keep your code hidden (in a binary file) or keep it clean. It is needed to reduce generality although in the first situation. It is explained here: http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file – Sheric Feb 25 '17 at 16:40
  • 1
    Explicit template instantiation is how you can go about reducing compile time of templates: https://stackoverflow.com/questions/2351148/explicit-template-instantiation-when-is-it-used – Ciro Santilli OurBigBook.com Aug 28 '20 at 16:44

16 Answers16

170

It is not possible to write the implementation of a template class in a separate cpp file and compile. All the ways to do so, if anyone claims, are workarounds to mimic the usage of separate 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 instructions 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 separate 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 behind separating interface from implementation is hiding implementation details in binary form. This is where you must separate the data structures and algorithms. Your template classes must represent only data structures not the algorithms. This enables you to hide more valuable implementation details in separate 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.

Michael Wildermuth
  • 5,762
  • 3
  • 29
  • 48
Sharjith N.
  • 1,872
  • 1
  • 13
  • 10
  • 3
    "it must be understood that template class is not a class at all" - wasn't it the other way around? Class template is a template. "Template class" is sometimes used in place of "instantiation of a template", and would be an actual class. – Xupicor Nov 08 '16 at 04:44
  • Just for reference, it's not correct to say there's no workarounds! Separating Data Structures from methods is also a bad idea as it is opposed by encapsulation. There's a great workaround that you can use in some situations (I believe most) here: http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file – Sheric Feb 25 '17 at 16:37
  • @Xupicor, you are right. Technically "Class Template" is what you write so that you can instantiate a "Template Class" and its corresponding object. However, I believe that in a generic terminology, using both terms interchangeably would not be all that wrong, the syntax for defining the "Class Template" itself begins with the word "template" and not "class". – Sharjith N. Sep 28 '17 at 08:53
  • @Sheric, I didn't say that there are no workarounds. In fact, all that's available are only workarounds to mimic separation of interface and implementation in case of template classes. None of those workarounds work without instantiating a specific typed template class. That anyway dissolves the whole point of genericity of using class templates. Separating data structures from algorithms is not the same as separating data structures from methods. Data structure classes can very well have methods like constructors, getters and setters. – Sharjith N. Sep 28 '17 at 08:57
  • The closest thing I just found to making this work is to use a pair of .h/.hpp files, and #include "filename.hpp" at the end of the .h file defining your template class. (below your closing brace for the class definition with the semicolon). This at least structurally separates them filewise, and is allowed because in the end, the compiler copy/pastes your .hpp code over your #include "filename.hpp". – Artorias2718 Jan 19 '20 at 23:37
  • Could you provide a brief Foo-Bar example? Because algorithms operate on data one way or another, so to fully understand, an example could be helpful. – Vassilis Apr 28 '22 at 19:10
102

It is possible, as long as you know what instantiations you are going to need.

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

template class stack<int>;

All non-template methods of stack will be instantiated, and linking step will work fine.

Paul Baltescu
  • 2,095
  • 4
  • 25
  • 30
Benoît
  • 16,798
  • 8
  • 46
  • 66
  • 9
    In practice, most people use a separate cpp file for this - something like stackinstantiations.cpp. – Nemanja Trifunovic Nov 12 '09 at 20:17
  • @NemanjaTrifunovic can you give an example of what stackinstantiations.cpp would look like? – qwerty9967 Mar 11 '13 at 15:16
  • 3
    Actually there are other solutions: http://www.codeproject.com/Articles/48575/How-to-define-a-template-class-in-a-h-file-and-imp – sleepsort Mar 18 '13 at 08:14
  • @Benoît I got an error error: expected unqualified-id before ‘;’ token template stack; Do you know why? Thanks! – camino Nov 26 '13 at 16:37
  • @camino Can you specify the environment (compiler) and the code you are trying to compile ? – Benoît Nov 27 '13 at 06:06
  • @Benoît Happy Thanks giving :) I am using ubuntu and gcc 4.8.1. I copy the code above of exscape, and add "template stack;" at the end of stack.cpp. Thanks. – camino Nov 27 '13 at 12:37
  • @camino: thanks, you too ! Can you show me the full contents of stack.cpp ? First questions that come to mind are : have you included and have you taken care of namespace std for stack ? – Benoît Nov 29 '13 at 06:14
  • @Benoît: my code are same as the codes of "@exscape", the only difference is I add "template stack;" at the end of stack.cpp. #include #include "stack.hpp" template stack::stack() { std::cerr << "Hello, stack " << this << "!" << std::endl; } template stack::~stack() { std::cerr << "Goodbye, stack " << this << "." << std::endl; } template stack; – camino Nov 29 '13 at 13:56
  • +1 And for people wanting to learn more: http://www.cplusplus.com/forum/articles/14272/ – Andrew Larsson Dec 05 '13 at 22:49
  • 3
    Actually, the correct syntax is `template class stack;`. – Paul Baltescu Jun 10 '14 at 19:07
  • Thanks Paul. I can't believe this (stupid) mistake of mine had stuck for so long ! – Benoît Jun 11 '14 at 21:20
9

You can do it in 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 has been discussed in Daniweb

Also in FAQ but using C++ export keyword.

Sadanand
  • 1,080
  • 3
  • 13
  • 30
  • 5
    `include`ing a `cpp` file is generally a terrible idea. even if you have a valid reason for this, the file - which is really just a glorified header - should be given an `hpp` or some different extension (e.g. `tpp`) to make very clear what's going on, remove confusion around `makefile`s targeting _actual_ `cpp` files, etc. – underscore_d Jan 15 '16 at 11:55
  • @underscore_d Could you explain why including a `.cpp` file is a terrible idea? – Abbas Sep 25 '16 at 10:21
  • 2
    @Abbas because the extension `cpp` (or `cc`, or `c`, or whatever) indicates that the file is a piece of the implementation, that the resulting translation unit (preprocessor output) is separately compilable, and that the contents of the file are compiled once only. it does not indicate that the file is a reusable part of the interface, to be arbitrarily included anywhere. `#include`ing an _actual_ `cpp` file would quickly fill your screen with multiple definition errors, and rightly so. in this case, as there _is_ a reason to `#include` it, `cpp` was just the wrong choice of extension. – underscore_d Sep 25 '16 at 11:22
  • @underscore_d So basically it is wrong just to use the `.cpp` extension for such use. But to use another say `.tpp` is completely alright, which would serve the same purpose but use a different extension for easier/quicker understanding? – Abbas Sep 25 '16 at 12:39
  • 1
    @Abbas Yes, `cpp`/`cc`/etc must be avoided, but it's a good idea to use something other than `hpp` - e.g. `tpp`, `tcc`, etc. - so you can reuse the rest of the filename and indicate that the `tpp` file, although it acts like a header, holds the out-of-line implementation of the template declarations in the corresponding `hpp`. So this post starts with a good premise - separating declarations and definitions to 2 different files, which can be easier to grok/grep or sometimes is required due to circular dependencies IME - but then ends badly by suggesting that the 2nd file have a wrong extension – underscore_d Sep 25 '16 at 13:44
  • I would recommend for this to use .inl extension instead of .cpp one. Most IDE are already configured to use .inl as a C/C++ header. So you keep your declarations on the .h and your implementations on the .inl – rxantos Dec 03 '18 at 07:27
4

No, it's not possible. Not without the export keyword, which for all intents and purposes doesn't really exist.

The best you can do is put your function implementations in a ".tcc" or ".tpp" file, and #include the .tcc file at the end of your .hpp file. However this is merely cosmetic; it's still the same as implementing everything in header files. This is simply the price you pay for using templates.

Charles Salvia
  • 52,325
  • 13
  • 128
  • 140
  • 4
    Your answer is not correct. You can generate code from a template class in a cpp file, given you know what template arguments to use. See my answer for more information. – Benoît Nov 12 '09 at 19:15
  • 2
    True, but this comes with the serious restriction of needing to update the .cpp file and recompile every time a new type is introduced which uses the template, which is probably not what the OP had in mind. – Charles Salvia Nov 12 '09 at 19:40
3

I believe there are two main reasons for trying to seperate templated code into a header and a cpp:

One is for mere elegance. We all like to write code that is wasy to read, manage and is reusable later.

Other is reduction of compilation times.

I am currently (as always) coding simulation software in conjuction with OpenCL and we like to keep code so it can be run using float (cl_float) or double (cl_double) types as needed depending on HW capability. Right now this is done using a #define REAL at the beginning of the code, but this is not very elegant. Changing desired precision requires recompiling the application. Since there are no real run-time types, we have to live with this for the time being. Luckily OpenCL kernels are compiled runtime, and a simple sizeof(REAL) allows us to alter the kernel code runtime accordingly.

The much bigger problem is that even though the application is modular, when developing auxiliary classes (such as those that pre-calculate simulation constants) also have to be templated. These classes all appear at least once on the top of the class dependency tree, as the final template class Simulation will have an instance of one of these factory classes, meaning that practically every time I make a minor change to the factory class, the entire software has to be rebuilt. This is very annoying, but I cannot seem to find a better solution.

Meteorhead
  • 480
  • 3
  • 13
3

Only if you #include "stack.cpp at the end of stack.hpp. I'd only recommend this approach if the implementation is relatively large, and if you rename the .cpp file to another extension, as to differentiate it from regular code.

lyricat
  • 1,988
  • 2
  • 12
  • 20
  • 4
    If you're doing this, you'll want to add #ifndef STACK_CPP (and friends) to your stack.cpp file. – Stephen Newell Nov 12 '09 at 17:47
  • Beat me to this suggestion. I too don't prefer this approach for style reasons. – luke Nov 12 '09 at 17:50
  • 2
    Yes, in such a case, the 2nd file should definitely not be given the extension `cpp` (or `cc` or whatever) because that's a stark contrast to its real role. It should instead be given a different extension that indicates it's (A) a header and (B) a header to be included at the _bottom_ of another header. I use `tpp` for this, which handily can also stand for `t`em`p`late im`p`lementation (out-of-line definitions). I rambled more about this here: http://stackoverflow.com/questions/1724036/splitting-templated-c-classes-into-hpp-cpp-files-is-it-possible/9992920#comment57362919_9992920 – underscore_d Sep 26 '16 at 09:23
2

Sometimes it is possible to have most of implementation hidden in cpp file, if you can extract common functionality foo all template parameters into non-template class (possibly type-unsafe). Then header will contain redirection calls to that class. Similar approach is used, when fighting with "template bloat" problem.

Konstantin Tenzin
  • 12,398
  • 3
  • 22
  • 20
2

The problem is that a template doesn't generate an actual class, it's just a template telling the compiler how to generate a class. You need to generate a concrete class.

The easy and natural way is to put the methods in the header file. But there is another way.

In your .cpp file, if you have a reference to every template instantiation and method you require, the compiler will generate them there for use throughout your project.

new 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;
}
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
}
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 8
    You dont need the dummey function: Use 'template stack;' This forces an instanciation of the template into the current compilation unit. Very useful if you define a template but only want a couple of specific implementations in a shared lib. – Martin York Nov 12 '09 at 19:34
  • @Martin: including all of the member functions? That's fantastic. You should add this suggestion to the "hidden C++ features" thread. – Mark Ransom Nov 12 '09 at 19:49
  • @LokiAstari I found an article on this in case anyone wants to learn more: http://www.cplusplus.com/forum/articles/14272/ – Andrew Larsson Dec 05 '13 at 22:49
2

If you know what types your stack will be used with, you can instantiate them expicitly in the cpp file, and keep all relevant code there.

It is also possible to export these across DLLs (!) but it's pretty tricky to get the syntax right (MS-specific combinations of __declspec(dllexport) and the export keyword).

We've used that in a math/geom lib that templated double/float, but had quite a lot of code. (I googled around for it at the time, don't have that code today though.)

Macke
  • 24,812
  • 7
  • 82
  • 118
2

The place where you might want to do this is when you create a library and header combination, and hide the implementation to the user. Therefore, the suggested approach is to use explicit instantiation, because you know what your software is expected to deliver, and you can hide the implementations.

Some useful information is here: https://learn.microsoft.com/en-us/cpp/cpp/explicit-instantiation?view=vs-2019

For your same example: Stack.hpp

template <class T>
class Stack {

public:
    Stack();
    ~Stack();
    void Push(T val);
    T Pop();
private:
    T val;
};


template class Stack<int>;

stack.cpp

#include <iostream>
#include "Stack.hpp"
using namespace std;

template<class T>
void Stack<T>::Push(T val) {
    cout << "Pushing Value " << endl;
    this->val = val;
}

template<class T>
T Stack<T>::Pop() {
    cout << "Popping Value " << endl;
    return this->val;
}

template <class T> Stack<T>::Stack() {
    cout << "Construct Stack " << this << endl;
}

template <class T> Stack<T>::~Stack() {
    cout << "Destruct Stack " << this << endl;
}

main.cpp

#include <iostream>
using namespace std;

#include "Stack.hpp"

int main() {
    Stack<int> s;
    s.Push(10);
    cout << s.Pop() << endl;
    return 0;
}

Output:

> Construct Stack 000000AAC012F8B4
> Pushing Value
> Popping Value
> 10
> Destruct Stack 000000AAC012F8B4

I however don't entirely like this approach, because this allows the application to shoot itself in the foot, by passing incorrect datatypes to the templated class. For instance, in the main function, you can pass other types that can be implicitly converted to int like s.Push(1.2); and that is just bad in my opinion.

Sriram Murali
  • 5,804
  • 2
  • 26
  • 32
1

You need to have everything in the hpp file. The problem is that the classes aren't actually created until the compiler sees that they're needed by some OTHER cpp file - so it has to have all the code available to compile the templated class at that time.

One thing that I tend to do is to try to split my templates into a generic non-templated part (which can be split between cpp/hpp) and the type-specific template part which inherits the non-templated class.

Aaron
  • 9,123
  • 5
  • 40
  • 38
0

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.

ChadNC
  • 2,528
  • 4
  • 25
  • 39
0

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 dislike this suggestion as a matter of style, but it may suit you.

luke
  • 36,103
  • 8
  • 58
  • 81
  • 1
    The glorified 2nd header being included should at least have an extension other than `cpp` to avoid confusion with _actual_ source files. Common suggestions include `tpp` and `tcc`. – underscore_d Jan 15 '16 at 11:59
0

The 'export' keyword is the way to separate out template implementation from template declaration. This was introduced in C++ standard without an existing implementation. In due course only a couple of compilers actually implemented it. Read in depth information at Inform IT article on export

Shailesh Kumar
  • 6,457
  • 8
  • 35
  • 60
0

1) Remember the main reason to separate .h and .cpp files is to hide the class implementation as a separately-compiled Obj code that can be linked to the user’s code that included a .h of the class.

2) Non-template classes have all variables concretely and specifically defined in .h and .cpp files. So the compiler will have the need information about all data types used in the class before compiling/translating  generating the object/machine code Template classes have no information about the specific data type before the user of the class instantiate an object passing the required data type:

        TClass<int> myObj;

3) Only after this instantiation, the complier generate the specific version of the template class to match the passed data type(s).

4) Therefore, .cpp Can NOT be compiled separately without knowing the users specific data type. So it has to stay as source code within “.h” until the user specify the required data type then, it can be generated to a specific data type then compiled

-3

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

Ahmad
  • 1