701

I have some template code that I would prefer to have stored in a CPP file instead of inline in the header. I know this can be done as long as you know which template types will be used. For example:

.h file

class foo
{
public:
    template <typename T>
    void do(const T& t);
};

.cpp file

template <typename T>
void foo::do(const T& t)
{
    // Do something with t
}

template void foo::do<int>(const int&);
template void foo::do<std::string>(const std::string&);

Note the last two lines - the foo::do template function is only used with ints and std::strings, so those definitions mean the app will link.

My question is - is this a nasty hack or will this work with other compilers/linkers? I am only using this code with VS2008 at the moment but will be wanting to port to other environments.

Leon Timmermans
  • 30,029
  • 2
  • 61
  • 110
Rob
  • 76,700
  • 56
  • 158
  • 197

13 Answers13

314

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:

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

Qix - MONICA WAS MISTREATED
  • 14,451
  • 16
  • 82
  • 145
Aaron N. Tubbs
  • 3,895
  • 1
  • 16
  • 6
  • 51
    Just to complement the answer, the referenced link answers the question positively, i.e. it is possible to do what Rob suggested and have the code to be portable. – ivotron May 01 '11 at 21:46
  • 281
    Can you just post the relevant parts in the answer itself? Why is such referencing even allowed on SO. I have no clue what to look for in this link as it has been heavily changed since. – Ident Aug 16 '15 at 21:57
172

For others on this page wondering what the correct syntax is (as did I) for explicit template specialisation (or at least in VS2008), its the following...

In your .h file...

template<typename T>
class foo
{
public:
    void bar(const T &t);
};

And in your .cpp file

template <class T>
void foo<T>::bar(const T &t)
{ }

// Explicit template instantiation
template class foo<int>;
Qix - MONICA WAS MISTREATED
  • 14,451
  • 16
  • 82
  • 145
namespace sid
  • 1,816
  • 1
  • 11
  • 5
  • 22
    Do you mean "for explicit CLASS template specialiastion". In that case will that cover every function that the templated class has ? – 0x26res Feb 21 '13 at 13:57
  • @Arthur seems not, I have some template methods stay in header and most of other methods in cpp, works fine. Very nice solution. – user1633272 Oct 03 '19 at 15:29
  • In the asker's case, they have a function template, not a class template. – user253751 Mar 06 '20 at 10:56
  • 1
    So, you can put multiple template class foo<...> at the bottom of certain file, right? So, one file for definitions for int, for example, Other for float, if there are any differences, if there are not differences you can just pul template class foo under int? Am I getting this right? – Petko Kamenov Mar 09 '21 at 12:23
  • I noticed my link time (clang) increased significantly taking this approach. – aj.toulan Aug 03 '21 at 18:30
  • 3
    I'm completely completely confused about your use of typename AND class, here.. – RichieHH Sep 06 '21 at 18:46
31

Your example is correct but not very portable. There is also a slightly cleaner syntax that can be used (as pointed out by @namespace-sid, among others).

However, suppose the templated class is part of some library that is to be shared...

Should other versions of the templated class be compiled?

Is the library maintainer supposed to anticipate all possible templated uses of the class?

An Alternate Approach

Add a third file that is the template implementation/instantiation file in your sources.

lib/foo.hpp - from library

#pragma once

template <typename T>
class foo {
public:
    void bar(const T&);
};

lib/foo.cpp - compiling this file directly just wastes compilation time

// Include guard here, just in case
#pragma once

#include "foo.hpp"

template <typename T>
void foo::bar(const T& arg) {
    // Do something with `arg`
}

foo.MyType.cpp - using the library, explicit template instantiation of foo<MyType>

// Consider adding "anti-guard" to make sure it's not included in other translation units
#if __INCLUDE_LEVEL__
  #error "Don't include this file"
#endif

// Yes, we include the .cpp file
#include <lib/foo.cpp>
#include "MyType.hpp"

template class foo<MyType>;

Organize your implementations as desired:

  • All implementations in one file
  • Multiple implementation files, one for each type
  • An implementation file for each set of types

Why??

This setup should reduce compile times, especially for heavily used complicated templated code, because you're not recompiling the same header file in each translation unit. It also enables better detection of which code needs to be recompiled, by compilers and build scripts, reducing incremental build burden.

Usage Examples

foo.MyType.hpp - needs to know about foo<MyType>'s public interface but not .cpp sources

#pragma once

#include <lib/foo.hpp>
#include "MyType.hpp"

// Declare `temp`. Doesn't need to include `foo.cpp`
extern foo<MyType> temp;

examples.cpp - can reference local declaration but also doesn't recompile foo<MyType>

#include "foo.MyType.hpp"

MyType instance;

// Define `temp`. Doesn't need to include `foo.cpp`
foo<MyType> temp;

void example_1() {
    // Use `temp`
    temp.bar(instance);
}

void example_2() {
    // Function local instance
    foo<MyType> temp2;

    // Use templated library function
    temp2.bar(instance);
}

error.cpp - example that would work with pure header templates but doesn't here

#include <lib/foo.hpp>

// Causes compilation errors at link time since we never had the explicit instantiation:
// template class foo<int>;
// GCC linker gives an error: "undefined reference to `foo<int>::bar()'"
foo<int> nonExplicitlyInstantiatedTemplate;
void linkerError() {
    nonExplicitlyInstantiatedTemplate.bar();
}

Note: Most compilers/linters/code helpers won't detect this as an error, since there is no error according to C++ standard. But when you go to link this translation unit into a complete executable, the linker won't find a defined version of foo<int>.


Alternate approach from: https://stackoverflow.com/a/495056/4612476

Cameron Tacklind
  • 5,764
  • 1
  • 36
  • 45
  • what does this buy you? You still need to edit foo-impl.cpp in order to add a new specialization. – MK. Mar 22 '17 at 14:16
  • 3
    Separation of implementation details (aka definitions in `foo.cpp`) from which versions are actually compiled (in `foo-impl.cpp`) and declarations (in `foo.h`). I dislike that most C++ templates are defined entirely in header files. That is counter to the C/C++ standard of pairs of `c[pp]/h` for each class/namespace/whatever grouping you use. People seem to still use monolithic header files simply because this alternative is not widely used or known. – Cameron Tacklind Mar 29 '17 at 20:06
  • 1
    @MK. I was putting the explicit template instantiations at the end of the definition in the source file at first until I needed further instantiations elsewhere (e.g. unit tests using a mock as the templated type). This separation allows me to add more instantiations externally. Furthermore, it still works when I keep the original as a `h/cpp` pair although I had to surround the original list of instantiations in an include guard, but I could still compile the `foo.cpp` as normal. I am still quite new to C++ though and would be interested to know if this mixed usage has any additional caveat. – WaterGenie Dec 28 '18 at 07:02
  • 4
    I think it is preferable to decouple `foo.cpp` and `foo-impl.cpp`. Do not `#include "foo.cpp"` in the `foo-impl.cpp` file; instead, add the declaration `extern template class foo;` to `foo.cpp` to prevent the compiler from instantiating the template when compiling `foo.cpp`. Ensure that the build system builds both `.cpp` files and passes both of the object files to the linker. This has multiple benefits: a) it's clear in `foo.cpp` that there is no instantiation; b) changes to foo.cpp do not require a recompilation of foo-impl.cpp. – Shmuel Levine May 29 '19 at 14:17
  • 10
    This is a very good approach to the problem of templates definitions that takes best of both worlds -- header implementation and instantiation for frequently used types. The only change I would make to this setup is to rename `foo.cpp` into `foo_impl.h` and `foo-impl.cpp` into just `foo.cpp`. I also would add typedefs for instantiations from `foo.cpp` to `foo.h`, likewise `using foo_int = foo;`. The trick is to provide users two header interfaces for a choice. When user needs pre-defined instantiation he includes `foo.h`, when user needs something out of order he includes `foo_impl.h`. – Wormer Oct 30 '19 at 20:04
  • 2
    Shouldn't `lib/foo.cpp` be `lib/foo.inl` so project-generating tools like cmake know it shouldn't be compiled directly? – idbrii Aug 10 '21 at 17:55
  • @idbrii If that's the standard you want to follow, you're welcome to do that. I don't like doing so because I like my C++ source files to have a `.cpp` file extension. – Cameron Tacklind Aug 10 '21 at 19:56
  • @idbrii There is no reason for it to be `.cpp` file as it includes nothing that couldn't be in a header; I would rename it as `.h` file. – VLL Apr 12 '23 at 06:25
  • 1
    @VLL Could could put all functions into a header. There are plenty of reasons to not. – Cameron Tacklind Apr 12 '23 at 07:15
27

This code is well-formed. You only have to pay attention that the definition of the template is visible at the point of instantiation. To quote the standard, § 14.7.2.4:

The definition of a non-exported function template, a non-exported member function template, or a non-exported member function or static data member of a class template shall be present in every translation unit in which it is explicitly instantiated.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 3
    What does *non-exported* mean? – Dan Nissenbaum Jun 12 '14 at 19:29
  • 2
    @Dan Visible only inside its compilation unit, not outside it. If you link multiple compilation units together, exported symbols can be used across them (and must have a single, or at least, in the case of templates, consistent definitions, otherwise you run into UB). – Konrad Rudolph Jun 12 '14 at 19:32
  • Thanks. I thought that all functions are (by default) visible outside the compilation unit. If I have two compilation units `a.cpp` (defining the function `a() {}`) and `b.cpp` (defining the function `b() { a() }`), then this will successfully link. If I'm right, then the above quote would seem not to apply for the typical case... am I going wrong somewhere? – Dan Nissenbaum Jun 12 '14 at 19:46
  • @Dan Trivial counterexample: `inline` functions – Konrad Rudolph Jun 12 '14 at 20:02
  • For *exported* functions (a typical case, if I understand correctly), though, from the quoted paragraph, would it not then be true that the definition of the template function does *not* need to be present in a translation unit in which the template function is explicitly instantiated? If so, this seems to violate the implication of the accepted answer, the answer being that it is a correct approach to explicitly instantiate the template function in the *same* source file (and hence the same translation unit) as where it is defined. If you have time, I'd love to have that clarified! Thanks. – Dan Nissenbaum Jun 12 '14 at 21:06
  • 1
    @Dan Function templates are implicitly `inline`. The reason being that without a standardised C++ ABI it’s hard/impossible to define the effect that this would otherwise have. – Konrad Rudolph Jun 12 '14 at 21:41
  • watch out, recursive Q&A :) – osirisgothra May 06 '15 at 23:39
  • @DanNissenbaum I think the *non-exported* refers to the [`export` keyword](https://stackoverflow.com/questions/5416872/using-export-keyword-with-templates). – ph3rin Feb 18 '21 at 18:43
17

This should work fine everywhere templates are supported. Explicit template instantiation is part of the C++ standard.

moonshadow
  • 86,889
  • 7
  • 82
  • 122
9

That is a standard way to define template functions. I think there are three methods I read for defining templates. Or probably 4. Each with pros and cons.

  1. Define in class definition. I don't like this at all because I think class definitions are strictly for reference and should be easy to read. However it is much less tricky to define templates in class than outside. And not all template declarations are on the same level of complexity. This method also makes the template a true template.

  2. Define the template in the same header, but outside of the class. This is my preferred way most of the times. It keeps your class definition tidy, the template remains a true template. It however requires full template naming which can be tricky. Also, your code is available to all. But if you need your code to be inline this is the only way. You can also accomplish this by creating a .INL file at the end of your class definitions.

  3. Include the header.h and implementation.CPP into your main.CPP. I think that's how its done. You won't have to prepare any pre instantiations, it will behave like a true template. The problem I have with it is that it is not natural. We don't normally include and expect to include source files. I guess since you included the source file, the template functions can be inlined.

  4. This last method, which was the posted way, is defining the templates in a source file, just like number 3; but instead of including the source file, we pre instantiate the templates to ones we will need. I have no problem with this method and it comes in handy sometimes. We have one big code, it cannot benefit from being inlined so just put it in a CPP file. And if we know common instantiations and we can predefine them. This saves us from writing basically the same thing 5, 10 times. This method has the benefit of keeping our code proprietary. But I don't recommend putting tiny, regularly used functions in CPP files. As this will reduce the performance of your library.

Note, I am not aware of the consequences of a bloated obj file.

Not a real meerkat
  • 5,604
  • 1
  • 24
  • 55
7

Let's take one example, let's say for some reason you want to have a template class:

//test_template.h:
#pragma once
#include <cstdio>

template <class T>
class DemoT
{
public:
    void test()
    {
        printf("ok\n");
    }
};

template <>
void DemoT<int>::test()
{
    printf("int test (int)\n");
}


template <>
void DemoT<bool>::test()
{
    printf("int test (bool)\n");
}

If you compile this code with Visual Studio - it works out of box. gcc will produce linker error (if same header file is used from multiple .cpp files):

error : multiple definition of `DemoT<int>::test()'; your.o: .../test_template.h:16: first defined here

It's possible to move implementation to .cpp file, but then you need to declare class like this -

//test_template.h:
#pragma once
#include <cstdio>

template <class T>
class DemoT
{
public:
    void test()
    {
        printf("ok\n");
    }
};

template <>
void DemoT<int>::test();

template <>
void DemoT<bool>::test();

// Instantiate parametrized template classes, implementation resides on .cpp side.
template class DemoT<bool>;
template class DemoT<int>;

And then .cpp will look like this:

//test_template.cpp:
#include "test_template.h"

template <>
void DemoT<int>::test()
{
    printf("int test (int)\n");
}


template <>
void DemoT<bool>::test()
{
    printf("int test (bool)\n");
}

Without two last lines in header file - gcc will work fine, but Visual studio will produce an error:

 error LNK2019: unresolved external symbol "public: void __cdecl DemoT<int>::test(void)" (?test@?$DemoT@H@@QEAAXXZ) referenced in function

template class syntax is optional in case if you want to expose function via .dll export, but this is applicable only for windows platform - so test_template.h could look like this:

//test_template.h:
#pragma once
#include <cstdio>

template <class T>
class DemoT
{
public:
    void test()
    {
        printf("ok\n");
    }
};

#ifdef _WIN32
    #define DLL_EXPORT __declspec(dllexport) 
#else
    #define DLL_EXPORT
#endif

template <>
void DLL_EXPORT DemoT<int>::test();

template <>
void DLL_EXPORT DemoT<bool>::test();

with .cpp file from previous example.

This however gives more headache to linker, so it's recommended to use previous example if you don't export .dll function.

TarmoPikaro
  • 4,723
  • 2
  • 50
  • 62
5

This is definitely not a nasty hack, but be aware of the fact that you will have to do it (the explicit template specialization) for every class/type you want to use with the given template. In case of MANY types requesting template instantiation there can be A LOT of lines in your .cpp file. To remedy this problem you can have a TemplateClassInst.cpp in every project you use so that you have greater control what types will be instantiated. Obviously this solution will not be perfect (aka silver bullet) as you might end up breaking the ODR :).

Red XIII
  • 5,771
  • 4
  • 28
  • 29
  • Are you certain it will break the ODR? If the instantiation lines in TemplateClassInst.cpp refer to the identical source file (containing the template function definitions), isn't that guaranteed not to violate the ODR since all definitions are identical (even if repeated)? – Dan Nissenbaum Jun 12 '14 at 19:36
  • Please, what is ODR? – nonremovable Jun 22 '18 at 11:45
  • @nonremovable: ODR stands for "One Definition Rule". See [here](https://en.cppreference.com/w/cpp/language/definition) for an explanation. – andreee Sep 16 '22 at 14:56
4

Yes, that's the standard way to do specializiation explicit instantiation. As you stated, you cannot instantiate this template with other types.

Edit: corrected based on comment.

Lou Franco
  • 87,846
  • 14
  • 132
  • 192
4

There is, in the latest standard, a keyword (export) that would help alleviate this issue, but it isn't implemented in any compiler that I'm aware of, other than Comeau.

See the FAQ-lite about this.

Ben Collins
  • 20,538
  • 18
  • 127
  • 187
  • 3
    AFAIK, export is dead because they are facing newer and newer issues, each time they resolve the last, making the overall solution more and more complicated. And the "export" keyword won't enable you to "export" from a CPP anyway (still from H. Sutter's anyway). So I say: Don't hold your breath... – paercebal Sep 22 '08 at 16:25
  • 2
    To implement export the compiler still requires the full template definition. All you gain is having it in a sort-of-compiled form. But really there's no point to it. – Zan Lynx Mar 12 '12 at 16:56
  • 2
    ...and it's *gone* from the standard, due to excessive complication for minimal gain. – DevSolar Aug 26 '15 at 13:04
3

None of above worked for me, so here is how y solved it, my class have only 1 method templated..

.h

class Model
{
    template <class T>
    void build(T* b, uint32_t number);
};

.cpp

#include "Model.h"
template <class T>
void Model::build(T* b, uint32_t number)
{
    //implementation
}

void TemporaryFunction()
{
    Model m;
    m.build<B1>(new B1(),1);
    m.build<B2>(new B2(), 1);
    m.build<B3>(new B3(), 1);
}

this avoid linker errors, and no need to call TemporaryFunction at all

KronuZ
  • 378
  • 2
  • 13
  • 1
    Your answer same as the question and it does not work! – Mahmut EFE Jan 24 '21 at 02:53
  • 1
    Down voted, but this code doesn't compile and work when you actually try and include the header file in another source file to start using this templated class. You will get unresolved symbol linker errors. – Code Doggo May 16 '22 at 05:57
1

Time for an update! Create an inline (.inl, or probably any other) file and simply copy all your definitions in it. Be sure to add the template above each function (template <typename T, ...>). Now instead of including the header file in the inline file you do the opposite. Include the inline file after the declaration of your class (#include "file.inl").

I don't really know why no one has mentioned this. I see no immediate drawbacks.

Didii
  • 1,194
  • 12
  • 36
  • 29
    The immediate drawbacks is it is fundamentally the same as just defining the template functions directly in the header. Once you `#include "file.inl"`, the preprocessor is going to paste the contents of `file.inl` directly into the header. Whatever reason you wanted to avoid the implementation going in the header, this solution doesn't solve that problem. – Cody Gray - on strike Jun 25 '13 at 03:38
  • 5
    - _and_ means you're, technically unnecessarily, burdening yourself w/ the task of writing all the verbose, mind-bending boilerplate needed by out-of-line `template` definitions. I get why people want to do it - to achieve the most parity with non-template declarations/definitions, to keep the interface declaration looking tidy, etc. - but it's not always worth the hassle. It's a case of evaluating the trade-offs on both sides and picking the _least bad_. ... until [`namespace class`](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0223r0.html) becomes a thing :O [_please be a thing_] – underscore_d Aug 02 '16 at 20:52
  • 2
    @Andrew It seems to have gotten stuck in the Committee's pipes, although I think I saw someone saying that wasn't intentional. I wish it had made it into C++17. Maybe next decade. – underscore_d Sep 14 '16 at 10:05
  • @CodyGray: Technically, this is indeed the same for the compiler and it is therefore not reducing the compile time. Still I think this is worth mentioning and practiced in a number of projects I have seen. Going down this road helps to separate Interface from the definition, which is a good practice. In this case it doesn't help with ABI compatibility or the like, but it eases reading and understanding the Interface. – kiloalphaindia May 07 '18 at 09:29
0

There is nothing wrong with the example you have given. But i must say i believe it's not efficient to store function definitions in a cpp file. I only understand the need to separate the function's declaration and definition.

When used together with explicit class instantiation, the Boost Concept Check Library (BCCL) can help you generate template function code in cpp files.

Benoît
  • 16,798
  • 8
  • 46
  • 66