37

Please refer to the first answer in this question about implementing templates.

Specifically, take note of this quote

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.

I bolded the part that I'm most interested in.
What's the significance of a .tpp file? I tried doing exactly what was suggested in that page and it worked. But then, I changed the file extension to any random gibberish (like .zz or .ypp) and it still worked! Is it supposed to work? Does it matter if it's .tpp or any other extension? And why not use a .cpp?

Here's another thing I'm confused about.
If my implementations were written in a .cpp and the header defined non-templated functions, then I'd only need to compile the .cpp file once, right? at least until I changed something in the .cpp file.

But if I have a header defining templated functions and my implementations are in a file with a random funky extension, how is it compiled? And are the implementations compiled every time I compile whatever source code #includes said header?

Manuel
  • 2,143
  • 5
  • 20
  • 22

4 Answers4

41

Does it matter if it's .tpp or any other extension? And why not use a .cpp?

It does not matter what the extension is, but don't use .cpp because it goes against conventions (it will still work, but don't do it; .cpp files are generally source files). Other than that it's a matter of what your codebase uses. For example I (and the Boost codebase) use .ipp for this purpose.

What's the significance of a .tpp file?

It's used when you don't want the file that contains the interface of a module to contain all the gory implementation details. But you cannot write the implementation in a .cpp file because it's a template. So you do the best you can (not considering explicit instantiations and the like). For example

Something.hpp

#pragma once

namespace space {

template <typename Type>
class Something {
public:
    void some_interface();
};

} // namespace space

#include "Something.ipp"

Something.ipp

#pragma once

namespace space {

template <typename Type>
void Something<Type>::some_interface() {
    // the implementation
}

} // namespace space

I thought the whole point of writing definitions in headers and the implementations in a separate file is to save compilation time, so that you compile the implementations only once until you make some changes

You can't split up general template code into an implementation file. You need the full code visible in order to use the template, that's why you need to put everything in the header file. For more see Why can templates only be implemented in the header file?

But if the implementation file has some funky looking file extension, how does that work in terms of compiling? Is it as efficient as if the implementations were in a cpp?

You don't compile the .tpp, .ipp, -inl.h, etc files. They are just like header files, except that they are only included by other header files. You only compile source (.cpp, .cc) files.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Curious
  • 20,870
  • 8
  • 61
  • 146
  • 1
    So, just to make sure I'm following, writing something like `#include "A.tpp"` in the header where `A.tpp` is the file with the implementations to the header is equivalent to simply writing the implementation in the header file itself? – Manuel Jun 27 '17 at 07:21
  • 3
    @Manuel it's exactly the same, it's essentially a copy paste of that file into the current file – Curious Jun 27 '17 at 07:22
  • 1
    But that must mean that the implementation code is compiled every time it's used in another file, right? If the header defined regular non-templated functions, then their implementations would only need to be compiled once. Is there no way to do this with templated functions? – Manuel Jun 27 '17 at 07:24
  • @Manuel there is this https://en.wikipedia.org/wiki/Precompiled_header, but I have never had to use it personally. Other than that there is no way to do this with template functions. There are cases where you can get away with things like this, for example with `std::string` (explicit instantiations) and then compile the source , for that see https://stackoverflow.com/questions/4933056/how-do-i-explicitly-instantiate-a-template-function – Curious Jun 27 '17 at 07:26
  • 1
    I see! Thank you so much, @Curious. I think now I'm finally getting the picture. And of course, I'm very grateful to everyone else responding to my question. – Manuel Jun 27 '17 at 07:27
9

Files extensions are meaningless to the preprocessor; there's nothing sacred about .h either. It's just convention, so other programmers know and understand what the file contains.

The preprocessor will allow you to include any file into any translation unit (it's a very blunt tool). Extensions like that just help clarify what should be included where.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
4

Does it matter if it's .tpp or any other extension? And why not use a .cpp?

It doesn't matter much which extension is actually used, as long it is different from any of the standard extensions used for C++ translation units.

The reasoning is to have a different file extension as they are usually detected by any C++ build systems for translation units (.cpp, .cc, ...). Because translating these as a source file would fail. They have to be #included by the corresponding header file containing the template declarations.

But if the implementation file has some funky looking file extension, how does that work in terms of compiling?

It needs to be #included to be compiled as mentioned.

Is it as efficient as if the implementations were in a cpp?

Well, not a 100% as efficient regarding compile time like a pure object file generated from a translation unit. It will be compiled again, as soon the header containing the #include statement changes.

And are the implementations compiled every time I compile whatever source code #includes said header?

Yes, they are.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
2

The file extensions of header files do not matter in C++, even though standard source-file extensions such as .cpp should be avoided.

However, there are established conventions. These help human programmers navigate the code. Calling template implementation files .tpp is one of such conventions.

Something nobody has mentioned yet is that some external tools might rely on such conventions.

For instance, I routinely employ a popular grep substitute which allows searching only in files of a given type. This program will recognize .tpp files as C++, but not, say, .zz files.

Also, code editors may display some default syntax highlighting based on the extension (like vscode).