43

Why should the implementation and the declaration of a template class be in the same header file? Could any of you explain it by example?

Aman Aggarwal
  • 3,905
  • 4
  • 26
  • 38
Haiyuan Zhang
  • 40,802
  • 41
  • 107
  • 134
  • 7
    they have to be visible within same compilation unit. they can be in different files if both are included – Anycorn Sep 20 '10 at 06:31
  • 2
    It's in fact not uncommon to split declaration and implementation in two files. The header will tehn usually include the implementation file. – MSalters Sep 20 '10 at 07:05
  • @MSalters: Which is problematic with template classes, which is what this question is about. I wish I could downvote comments. – Lightness Races in Orbit Mar 03 '11 at 12:23
  • 4
    @Tomalak Geret'kal: Not at all. You have a declaration in "Foo.h" and definitions in "Foo.impl". The last line of "foo.h" before the header guard is "#include "Foo.impl". After the preprocessor has run, there is no difference anymore. They might be in different files, but they end in the same translation unit(s) - and that's what matters to compilers. – MSalters Mar 03 '11 at 12:26
  • @MSalters: Right, ok. Actually I managed to read your last sentence completely backwards. :) – Lightness Races in Orbit Mar 03 '11 at 12:28

4 Answers4

26

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.

Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
5

The definition of a class template and the implementation of its member functions has to be visible to every place that instantiates it with a distinct type. i.e. in order to instantiate myTemplate<int> you need to see the full definition and implementation of myTemplate.

The easiest way to do this is to put the definition of the template and its member functions in the same header, but there are other ways. For example, you could put the member function implementations in a separate file that was included separately. You could then include it from the first header, or only include the implementation file where you needed it.

For example, one practise is to explicitly instantiate a template for distinct set of parameters in one .cpp file and declare those instantiations extern in the header. This way, those instantiations can be used in other source files without requiring the implementation of the template member functions to be visible. However, unless you include the implementation file you won't be able to use other sets of template parameters.

i.e. if you have myTemplate<int> and myTemplate<std::string> defined as extern then you can use them fine, but if myTemplate<double> is not defined extern then you cannot use that without the implementation.

Anthony Williams
  • 66,628
  • 14
  • 133
  • 155
4

In the case of a normal class, the declaration is just enough for compilation, and the corresponding definitions will be linked.

In the case of templates, the compiler also needs the definition to generate the code.

The difference is better explained in the C++ FAQ.

Dennis
  • 56,821
  • 26
  • 143
  • 139
liaK
  • 11,422
  • 11
  • 48
  • 73
4

They don't have to.

What is necessary is for the template definition to be visible at the point of instantiation (where it's used) so that the compiler can derive the class / function from the template at this point.

However it is extremely common to use two header files for template classes:

// foo_fwd.hpp
template <typename T, typename U> struct Foo;

// foo.hpp
#include "foo_fwd.hpp"

template <typename T, typename U> struct Foo { typedef std::pair<T,U> type; };

This allows those who do not need the full template definition to include a somewhat lighter header, for example:

//is_foo.hpp
#include <boost/mpl/bool.hpp>
#include "foo_fwd.hpp"

template <typename Z>
struct is_foo: boost::mpl::false_ {};

template <typename T, typename U>
struct is_foo< Foo<T,U> >: boost::mpl::true_ {};

which can speed up compilation-time a bit.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722