Why Can Templates Only Be Implemented in the Header File

Why can templates only be implemented in the header file?

Caveat: It is not necessary to put the implementation in the header file, see the alternative solution at the end of this answer.

Anyway, the reason your code is failing is that, when instantiating a template, the compiler creates a new class with the given template argument. For example:

template<typename T>
struct Foo
{
T bar;
void doSomething(T param) {/* do stuff using T */}
};

// somewhere in a .cpp
Foo<int> f;

When reading this line, the compiler will create a new class (let's call it FooInt), which is equivalent to the following:

struct FooInt
{
int bar;
void doSomething(int param) {/* do stuff using int */}
}

Consequently, the compiler needs to have access to the implementation of the methods, to instantiate them with the template argument (in this case int). If these implementations were not in the header, they wouldn't be accessible, and therefore the compiler wouldn't be able to instantiate the template.

A common solution to this is to write the template declaration in a header file, then implement the class in an implementation file (for example .tpp), and include this implementation file at the end of the header.

Foo.h

template <typename T>
struct Foo
{
void doSomething(T param);
};

#include "Foo.tpp"

Foo.tpp

template <typename T>
void Foo<T>::doSomething(T param)
{
//implementation
}

This way, implementation is still separated from declaration, but is accessible to the compiler.

Alternative solution

Another solution is to keep the implementation separated, and explicitly instantiate all the template instances you'll need:

Foo.h

// no implementation
template <typename T> struct Foo { ... };

Foo.cpp

// implementation of Foo's methods

// explicit instantiations
template class Foo<int>;
template class Foo<float>;
// You will only be able to use Foo with int or float

If my explanation isn't clear enough, you can have a look at the C++ Super-FAQ on this subject.

Templates, coding only in header file?

Separating the declaration and the interface documentation from the implementation like you generally do with header (*.h) and source files (*.cpp) is generally not possible with templates due to the C++ compilation process.

In the compilation process all the header files are just included into the source files they are called from, then these source files are processed independently and finally all the resulting object files linked together into an executable. Templates are functions for generic data-types which are only instantiated for the data-types they are called with. This means a template function does not create any code as long as it is not instantiated by somebody with valid template arguments. Somehow you have to make sure that the template is instantiated with the data types required from all the source files that access the template function.

  • If you put the declaration in the header file and the implementation into the source file (like you generally do for functions) only those versions are instantiated that are know inside this particular source file. This means any other source file requiring a different set of parameters might result in a linker error as it is not aware that the source file does not hold the correct combination of template parameters making this not portable.
  • You could instantiate all the required versions manually which reduces overhead but generally this makes you lose a lot of flexibility as you have to define beforehand which template parameters will be used in other translatory units.
  • Finally you can simple leave the declaration and the implementation in the header file. This slows down the compilation process as all the contents of the header have to be pasted into all the source files calling it. Therefore some people are no fans of heavily templated libraries such as Boost but it gives you the most flexibility. This effect can though be reduced by features like pre-compiled headers. In order to make this more easily readable again some libraries separate declaration (and documentation) from the implementation by putting the declaration in *.h files and define the implementation in *.hpp-files (similar to * .cpp, see here).

So generally it depends on the usage: If you know that a particular template function is only used inside a particular source file you can put documentation, declaration and implementation into the source file (instead of the header). If you want to share the template function with several source files put the declaration and implementation inside the header. This is generally the standard way as it is most flexible. If you write a fully templated library then probably separating declaration and documentation in *.h files and implementation in *.hpp files probably makes the most sense but mainly just for having a simpler overview. Anyways it is completely normal to not have a clean separation between declaration and implementation for some functions and therefore some header files might be lacking a corresponding source file.

c++ template and header files [duplicate]

Headers.

It's because templates are instantiated at compile-time, not link-time, and different translation units (roughly equivalent to your .cpp files) only "know about" each other at link-time. Headers tend to be widely "known about" at compile-time because you #include them in any translation unit that needs them.

Read https://isocpp.org/wiki/faq/templates for more.

C++ template function compiles in header but not implementation

The problem you're having is that the compiler doesn't know which versions of your template to instantiate. When you move the implementation of your function to x.cpp it is in a different translation unit from main.cpp, and main.cpp can't link to a particular instantiation because it doesn't exist in that context. This is a well-known issue with C++ templates. There are a few solutions:

1) Just put the definitions directly in the .h file, as you were doing before. This has pros & cons, including solving the problem (pro), possibly making the code less readable & on some compilers harder to debug (con) and maybe increasing code bloat (con).

2) Put the implementation in x.cpp, and #include "x.cpp" from within x.h. If this seems funky and wrong, just keep in mind that #include does nothing more than read the specified file and compile it as if that file were part of x.cpp In other words, this does exactly what solution #1 does above, but it keeps them in seperate physical files. When doing this kind of thing, it is critical that you not try to compile the #included file on it's own. For this reason, I usually give these kinds of files an hpp extension to distinguish them from h files and from cpp files.

File: dumper2.h

#include <iostream>
#include <string>
#include <vector>

void test();
template <class T> void dumpVector( std::vector<T> v,std::string sep);
#include "dumper2.hpp"

File: dumper2.hpp

template <class T> void dumpVector(std::vector<T> v, std::string sep) {
typename std::vector<T>::iterator vi;

vi = v.begin();
std::cout << *vi;
vi++;
for (;vi<v.end();vi++) {
std::cout << sep << *vi ;
}
std::cout << "\n";
return;

}

3) Since the problem is that a particular instantiation of dumpVector is not known to the translation unit that is trying to use it, you can force a specific instantiation of it in the same translation unit as where the template is defined. Simply by adding this: template void dumpVector<int>(std::vector<int> v, std::string sep); ... to the file where the template is defined. Doing this, you no longer have to #include the hpp file from within the h file:

File: dumper2.h

#include <iostream>
#include <string>
#include <vector>

void test();
template <class T> void dumpVector( std::vector<T> v,std::string sep);

File: dumper2.cpp

template <class T> void dumpVector(std::vector<T> v, std::string sep) {
typename std::vector<T>::iterator vi;

vi = v.begin();
std::cout << *vi;
vi++;
for (;vi<v.end();vi++) {
std::cout << sep << *vi ;
}
std::cout << "\n";
return;
}

template void dumpVector<int>(std::vector<int> v, std::string sep);

By the way, and as a total aside, your template function is taking a vector by-value. You may not want to do this, and pass it by reference or pointer or, better yet, pass iterators instead to avoid making a temporary & copying the whole vector.

Elegant solution to implementing c++ templates

Why is it so?
As templates compiles through two phases in first phase compiler checks mostly for syntactical errors. If there is no error found in your template is legal to be used, but at this stage compiler do not generate any code for it. And in the second phase compiler will generate the code for all the class members function, of templated functions you used.

Because templates are evaluated at compile time. So what happens when compiler compiles it? For example if you defined a template in templated.hpp file and its implementation in implementation.cpp file. Compiler compiles each file separately into an object and then linker link them together. As templates are evaluated at compile time so compiler need its implementation at compile time, which is not available if you are having it in different implementation file. So linkers complains to you that I could not find implementation for type T for your this template. This all happens at compile time.

So far until C++20 or even C++23 templates are still needed to be evaluated at compile time albeit C++ has added new concept modules, I am not sure it can be used this way, but you can read about it here.

Why should the implementation and the declaration of a template class be in the same header file? [duplicate]

The compiler needs to have access to the entire template definition (not just the signature) in order to generate code for each instantiation of the template, so you need to move the definitions of the functions to your header.

For more details read about The Inclusion Model.



Related Topics



Leave a reply



Submit