0

I am trying to create and use a template function. This template function will be visible to multiple different source files. I only want to use this function with certain template parameters. I also want this to compile once. Therefore, I think I should explicitly instantiate the template in the instances I want it available in the source file where it is defined.

This is effectively what I have so far:

mytemplate.h

template <typename T>
void foo(T* thing, std::string other);

mytemplate.cpp

template <typename T>
void foo(T* thing, std::string other)
{
  doStuff(thing)
}

template void foo<MyType1>(MyType1* thing, std::string other);
template void foo<MyType2>(MyType2* thing, std::string other);

main1.cpp

#include mytemplate.h

...
foo<MyType1>(thing1, other1);
foo<MyType2>(thing2, other2);
...

main2.cpp

#include mytemplate.h

...
foo<MyType1>(thing, other);
...

My questions are:

  • Will this compile the explicit template instances only once?
  • Will the template still be able to be implicitly instantiated elsewhere in the code with different template parameters?

Note that the codebase I am working on is using C++ 14.

  • the implementation isn't in the header file so can't be instantiated even if other code tries to, see https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file – Alan Birtles May 09 '23 at 07:29
  • 1
    Why not just use simple non-template function overloading? – Jason May 09 '23 at 07:29
  • 1
    Also read about [Why can templates only be implemented in the header file?](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) – Jason May 09 '23 at 07:30
  • 2
    Maybe I'm off base here, but isn't this kind of situation what C++11's "*extern templates*" is meant to address? Sorry, I just learned about this feature tonight, never seen it used in practice before. – Remy Lebeau May 09 '23 at 07:31
  • 1
    @RemyLebeau Yes that feature( which is called *explicit instantiation declaration* and *explicit instantiation definition*) is what should be used here. Though I would suggest just using non-template function overloading if there is no need for templates. – Jason May 09 '23 at 07:32
  • @monkey_brain If you can try creating a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) and test out your example on [onlinegdb](https://www.onlinegdb.com/) and then sharing a link to that example in your question. Also read about *"explicit instantiation declaration"* etc. – Jason May 09 '23 at 07:38

2 Answers2

0

In your case, since the cpp files can't see the definition of the template class, you'll simply get compiler errors.

The right solution is to use extern template

template <typename T>
void foo(T* thing, std::string other);

//tell compiler to assume that some other cpp file defines these
//therefore, it doens't need the definition
extern template void foo(MyType1* thing, std::string other);
extern template void foo(MyType2* thing, std::string other);

And then in one cpp file:

template <typename T>
void foo(T* thing, std::string other) {}
//tell compiler to instantiate these right now.
template void foo(MyType1* thing, std::string other);
template void foo(MyType2* thing, std::string other);

Now only that one cpp file will instantiate those templates, and your code will compile faster, and link faster.

http://coliru.stacked-crooked.com/a/9c7c5f375d1b2d2b

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
-1

Question 1) Depends. If you use #ifndef, #define, and #endif, the compilation of your code should only occur once for the explicit instantiation declaration.

#ifndef YOUR_CLASS_H
#define YOUR_CLASS_H
... // Definition details
#endif //YOUR_CLASS_H

Even the usage of the above may not fully restrict recompilation. If you have multiple libraries/packages for instance, each library/package will compile its own version. Does it matter in the end for the majority of use cases? No, not really. C++ Modules when supported by all compilers and build systems will eventually eliminate these concerns.

Question 2) Yes, other instantiations can occur if called with different template parameters.

Bonus 1: The usage of

#pragma once

does not always work as intended. I forget the details, but the older style outlined above should work as intended always.

Bonus 2: There are limited options available in C++14 to restrict templates, but you should look into C++20 Concepts. The mechanisms to build Concepts can be applied in C++14. Small syntax differences may exist.

Bonus 3: As noted in the comment sections, templates should be defined and implemented in header files.