12

Normally when I create a class, I create a header and a source for that class. I have heard that with a template class, you have to put the function implementation in the header. I tried doing it both ways, and got compilation errors the first way. The second way worked fine. However, I like to organize my code into headers and source files, so is it possible to put the function implementations into a source file? (Maybe it requires special compilation flags or syntax?) Or should I just keep em in the header?

Thanks!

Andreas Magnusson
  • 7,321
  • 3
  • 31
  • 36
cat pants
  • 1,485
  • 4
  • 13
  • 22

5 Answers5

18

Generally, all template code must be in a header file since the compiler needs to know the complete type at the point of instantiation.

As Aaron says below it is possible to put the implementation details in a .cpp-file in the specific case where you know on before hand all possible types the template will be instantiated with and explicitly instantiate it with those types. You'll then get a linker error if the template gets instantiated with another type somewhere in your code.

A quite common general solution to at least visually separate interface from implementation is to put all implementation in a .inc (or .tcc or .ipp)-file and include it at the end of the header file.

Note that the syntax for putting template class members outside the class-definition (whether you use the specific solution or the general) is slightly cumbersome. You'll need to write:

// in test.h
template <class A>
class Test
{
public:
  void testFunction();
};

#include "test.inc"

// in test.inc    
template <class A>
void Test<A>::testFunction()
{
  // do something
}
Andreas Magnusson
  • 7,321
  • 3
  • 31
  • 36
  • 6
    A common extension used for this is `.tcc` (as in "template C++"). – Matteo Italia Dec 28 '11 at 23:54
  • 4
    Boost uses the extension `.ipp` for this (to match `.hpp` for headers and `.cpp` for source files). – ildjarn Dec 29 '11 at 01:28
  • 1
    I believe you can call your template implementation files anything, just as long as it's consistent in the project (and follow company guidelines). – Andreas Magnusson Dec 29 '11 at 13:58
  • 1
    You don't always need to put the template code in the header (see my answer). If you are making a library available to be used by others, then you probably do need to put the code in the header. But often you will be controlling your own project and you will know exactly which templates you will be instantiating and you will able to instatiate them in the header, leaving the implementation to a conventional cpp file. – Aaron McDaid Dec 30 '11 at 01:11
  • See the answers to this question for more examples, this exact question has been asked before (and answered correctly!) http://stackoverflow.com/a/2351622/146041 – Aaron McDaid Dec 30 '11 at 11:30
15

(Edited: This is slightly more robust version which allows the implementation to be compiled into a separate .o file. The template should be explicitly instantiated at the end of the implementation cpp file. Perhaps this was only an issue for g++.)

You don't need to put the implementations in the header if you know which templates will be instantiated and can list them in the header implementation file. For example, if you know that you will only use int and std::string, then you can put this in the header file:

// test.h
template <class A>
class Test
{
public:
  void f();
};

and put the implementation of f() into a normal test.cpp file:

// test.cpp
#include "test.h"
template <class A> void Test<A>::f() {
   // implementation
}
template class Test<int>;
template class Test<string>;

Those last two lines explicitly instantiate the template classes. It is better to put this at the end of the implementation file, after it has seen the implementations of the member functions. Then you can compile it to a .o file g++ -c test.cpp. This test.o file will contain complete implementations of both Test<int> and Test<string> and can be linked without any difficulty in the rest of your application.

It works, but is it a good idea? It depends on context. In many cases, this works very well. If you are writing a template for 'internal' use in your project, then you know which templates will be instantiated and which will not. But if instead you're making something available to the public which must be very flexible, then you will need to include the implementations in the header file.

A tip: Even if it's for public consumption, take a look at the methods and see if there are any methods whose parameters and return type are independent of the template parameters. If so, you could place them into a Base class as (pure) virtual functions. This Base class doesn't use any templates and hence you may be able to use this Base* in much of your application (template <class A> class Test : public Base { ..., allowing you to limit the reach of the templated code throughout your application. I found this useful recently when much of the underlying behaviour and construction of a class depended on the template parameters, but the interface to the already-constructed object did not depend on the template parameters.

Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88
5

To answer the original question: no, the definitions of [member] function templates don't have to go into the header. However, the compiler needs to see the definition to instantiate the template. For templates instantiated with many different types you want the templates to be implicitly instantiated when they are used. This is e.g. the case for class templates like std::vector<...> and for function templates like std::copy(...). In this case it is almost certainly impractical to separate the template definition from its declaration although I personally put the definitions into a separate file included at the bottom of the header file.

For templates instantiated with only a few types like the stream classes or std::basic_string<...> it is often better to define the function templates in a separate header-like file which is only included in implementation files which explicitly instantiates them. This way the effort of instantiating the template is only spent once rather than in every translation unit using it. Especially for the stream classes this makes a huge difference (primarily for compile and link time but on some systems also for executable size). ... and I'm pretty sure hardly anybody has gone to the trouble of using the stream classes with different character types than char and wchar_t (hint: it is non-trivial to arrange for the various facets to be implemented and present in the std::locale). The technique of explicitly instantiating templates also works well if there is only a limited set of types with which the template is intended to work.

Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
4

While it is technically the case that you can separate your implementation from your interface the syntax for templates gets so annoying to type repeatedly I would strongly recommend that you just hold your nose and put the implementation in your class until you get over the smell.

template <class X>
class klass_t {
public:
    void f();
    void g();
    void h();
};

template <class X>
void klass_t<X>::f() { ... }

template <class X>
void klass_t<X>::g() { ... }

template <class X>
void klasS_t<X>::h() { ... }

Would have been:

template <class X>
class klass_t {
public:
    void f() { ... }
    void g() { ... }
    void h() { ... }
};

Now imagine you want to add another template parameter (as in the following). Now you have to change the template argument lists in n places rather than just one.

template <class X, class Y>
class klass_t {
public:
    void f();
    void g();
    void h();
};

Unless you have a good reason not to, it is a lot easier on your fingers to just put everything in the class.

Antony Hatchkins
  • 31,947
  • 10
  • 111
  • 111
Bowie Owens
  • 2,798
  • 23
  • 20
  • Good point, but it has little to do with the question asked. – Antony Hatchkins Dec 06 '13 at 20:26
  • 1
    @AntonyHatchkins thanks for fixing the typo. WRT the relevance of my answer, once you establish that something is possible the next question worth considering is often whether it is advantageous. Yes, it is possible to separate implementation from interface with templates but because calling code is usually dependent on the implementation there is little advantage in doing so. I thought then, and still think, that it is more helpful to explain why you would not want to separate interface and implementation even though it is possible. – Bowie Owens Dec 09 '13 at 03:11
  • Come on, I didn't downvote you :) Thanks for your answer! My tone was due to the fact that there was a word 'header' in the question. And no word 'header' in your answer. It makes a huge difference. 'Technically possible' here is a bit too optimistic. The burden of explicit instantiation for all imaginable (existing and future) template parameters is much worse than just adding an additional parameter to template list when the list grows. – Antony Hatchkins Dec 09 '13 at 04:13
2

Template implementations need to be known at compile-time. That means the implementations must be visible to the compiler. There's no way to go around this.

If you want to keep implementation details a secret, there's no way to do this. You can of course obfuscate your code, but that's not much of an impediment.

If your only concern is code organization, you can create a separate include file with the implementations and include it at the end of your main header (much as Andreas' suggestion).

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 1
    You can put the implementations of template class member functions in a conventional cpp file, in certain circumstances. See my answer. – Aaron McDaid Dec 30 '11 at 01:13
  • @AaronMcDaid that's not a very good idea. It violates loose coupling. You can't extend the template outside the same module. – Luchian Grigore Dec 30 '11 at 06:27
  • First, you agree it's possible to hide the implementations from all but one of the cpp files? Loose coupling is not necessary if you know which templates will be used. It depends on context, and there are occasions where the developer knows which templates will be instantiated and which will not. – Aaron McDaid Dec 30 '11 at 11:26