C++ Template and Header Files

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.

c++ template and header files

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.

Templated Classes using header and source file

What is the proper way to do this with the implementation include at the bottom of the header file?

Put the include guards into your header file, including the implementation #include directive:

#ifndef __FOO_H
#define __FOO_H
// Foo.h
template <typename T>
struct Foo
{
void doSomething(T param);
};

#include "Foo.tpp"

#endif

You may also add the guards to Foo.tpp, but in the situation you posted it will not make much sense.

Would the include guards on my .cpp file prevent the compiler from creating the templates class/function for other types since it can now only be included once?

Typically you don't need include guards in *.cpp files at all, as you don't include them anywhere. Include guards are only needed in those files which are included into multiple translation units. And of course, those guards will not prevent instantiating the templates for other types, since it is what templates are designed for.

Isn't part of the reason for using header files in the first place is to prevent code from being recopied every time it is included, to keep a short compilation time? So what is the performance effect of templated functions (since they have to be defined in header) versus simply overloading a function/class? When should each be used?

Here you raise a big, platform-dependent and a bit opinion-based topic. Historically, include files were used to prevent code copying, as you said. It was enough to include function declarations (headers, not definitions) into multiple translation units, and then link them with a single copy of the compiled code for included functions.

Templates compile much slower than non-template functions, so implementing template export (separate header/implementation compilation for templates) isn't worth saving compilation time.

For some discussions and good answers on template performance, check these questions:

  • Is Template Metaprogramming faster than the equivalent C code?
  • C++ templates for performance?
  • Do c++ templates make programs slow?

In short, sometimes templates allow you to make some decisions in compile time instead of runtime, making the code faster. Anyway, the only proper way to determine if the code became faster or not, is to run performance tests in real-world environment.

Finally, templates are more about design, not about performance. They allow you to significantly reduce code duplication and conform DRY principle. A banal example of it are functions like std::max. A more interesting example is Boost.Spirit, which uses templates for building parsers entirely in compile time.

How to include a header file in c++?

In practice, a C++14 compiler needs to know for every aggregate type (in particular instantiated template classes) its size, alignment, vtable (if any) and sequence of fields -with their type and alignment-.

Hence, templates are practically not abstract types, even if programmers should view them that way.

Therefore, standard containers headers (like <vector>, <map> etc...) are generally including a lot of internal stuff defining the internal implementation of the template, and all the template member functions are inlined.

In practice, a standard header like <vector> is expanded to a lot of stuff (about ten thousand lines of C++ on my GCC 6 compiler on Linux).

Try the following command (it is preprocessing) with a simple file mytest.cc having #include <vector>:

 g++ -C -E -H -Wall mytest.cc > mytest.ii

The -H option shows all the internal included files. The -C -E is asking for preprocessed form with comments into mytest.ii. Then look with an editor (or a pager) into the generated mytest.ii; it would be quite big.

And that is why C++ compilation is often slow.

Modules are a future feature of C++ which could help. See this question.

If I've separated a template into a header and source, is there any way to compile it to its own object file?

Is there no way at all around this?

Yes, there is. If you instantiate a template explicitly in the translation unit where the functions are defined, then you can use those instances in other translation units.

But that of course limits what template arguments can be used to those that you've chosen for explicit instantiation. For unconstrained template arguments, there's no way around defining the functions in all translation units (where they are ODR-used).

Storing C++ template function definitions in a .CPP file

The problem you describe can be solved by defining the template in the header, or via the approach you describe above.

I recommend reading the following points from the C++ FAQ Lite:

  • Why can’t I separate the definition of my templates class from its declaration and put it inside a .cpp file?
  • How can I avoid linker errors with my template functions?
  • How does the C++ keyword export help with template linker errors?

They go into a lot of detail about these (and other) template issues.



Related Topics



Leave a reply



Submit