21

I've just been reading about template explicit instantiation:

template struct MyStruct<long>;

It was described as "quite rare", so under what circumstances would it be useful?

Rost
  • 8,779
  • 28
  • 50
Mark Ingram
  • 71,849
  • 51
  • 176
  • 230

4 Answers4

17

One of the use cases is to hide definitions from the end-user.

tpl.h:

template<typename T>
void func(); // Declaration

tpl.cpp:

template<typename T>
void func()
{
    // Definition
}

template void func<int>(); // explicit instantiation for int
template void func<double>();  // explicit instantiation for double

main.cpp

#include "tpl.h"
int main()
{
    func<double>(); // OK
    func<int>(); // OK
    // func<char>(); - Linking ERROR
}
Evgeny Panasyuk
  • 9,076
  • 1
  • 33
  • 54
  • So the definition doesn't become visible outside of the translation unit, except for the explicit instantiations? Thanks. – Mark Ingram Oct 25 '12 at 13:40
  • @Mark Ingram, Source code of "func" is not visible outside of translation units. Explicit instantiation generates code (binary) in corresponding object file. When user uses template function without definition(in that case in main.cpp), then dependency is resolved during linking – Evgeny Panasyuk Oct 25 '12 at 13:55
  • Thanks, this is exactly what I've used it for. I have a vector2 class, but I only want the float version to be available initially. So I've used explicit template instantiation for vector2. – Mark Ingram Oct 29 '12 at 09:14
10

Explicit instantiation is designed to optimize template libraries usage providing some of (mostly used) template instances in compiled binary form instead of source code form. This will reduce compile and link time for end-user applications. E.g. std::basic_string<char> and std::basic_string<wchar_t> can be explicitly instantiated in STL distribution avoid work on its instantiation in each translation unit.

Explicit instantiation is also useful when you want to encapsulate template implementation and you want this template to be used only with well-known set of types. In this case you can place only declarations of template functions (free or members) in header file (.h/.hpp) and define them in translation unit (.cpp).

Example:

 // numeric_vector.h
 //////////////////////////////////////////////////
 template <typename T> class numeric_vector
 {
    ...
    void sort();
 };


 // numeric_vector.cpp
 //////////////////////////////////////////////////
 // We know that it shall be used with doubles and ints only,
 // so we explicitly instantiate it for doubles and ints
 template class numeric_vector<int>;
 template class numeric_vector<double>;

 // Note that you could instantiate only specific
 // members you need (functions and static data), not entire class:
 template void numeric_vector<float>::sort();

 template <typename T> void numeric_vector<T>::sort()
 {
   // Implementation
   ...
 }

Also explicit instantiation can be useful when you need instantiated type from template but inside some syntax construction that doesn't trigger instantiation itself, e.g. some compiler-specific meta-feature like __declspec(uuid) in Visual Studio.

Note the difference with another technique that could be used for implementation encapsulation - explicit specialization. With explicit specialization you must provide specific definition for each type to be specialized. With explicit instantiation you have single template definition.

Consider the same example with explicit specialization:

Example:

 // numeric_vector.h
 //////////////////////////////////////////////////
 template <typename T> class numeric_vector
 {
    ...
    void sort();
 };

 template <> class numeric_vector<int>
 {
    ...
    void sort();
 };

 template <> class numeric_vector<double>
 {
    ...
    void sort();
 };

 // Specializing separate members is also allowed
 template <> void numeric_vector<float>::sort();

 // numeric_vector.cpp    
 //////////////////////////////////////////////////
 void numeric_vector<int>::sort()
 {
   // Implementation for int
   ...
 }

 void numeric_vector<double>::sort()
 {
   // Implementation for double
   ...
 }

 void numeric_vector<float>::sort()
 {
   // Implementation for float       
   ...
 }
Community
  • 1
  • 1
Rost
  • 8,779
  • 28
  • 50
5

Having an explicit specialization allows you to hide the implementation, which, as you know, is usually impossible with templates.

I've seen this technique only once in a library that handled geometry, and they'd provide their own vector class.

So you could use

lib::Vector<MyShape>

with some basic functionality that lib::Vector provided, and basic implementations, and if you used it with their classes (some, not all)

lib::Vector<lib::Polygon>

you would use the explicit specialization. You wouldn't have access to the implementation, but I'm betting some hardcore optimizations were going on behind the scenes there.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • You're talking about specialization, not instantiation? – Mark Ingram Oct 25 '12 at 13:41
  • I'm talking about both. When you write `Vector` you specialize the template, and having it in the header that defines the template also instantiates it, so you can move its implementation to the source file. – Luchian Grigore Oct 25 '12 at 13:43
  • Explicit specialization and explicit instantiation are quite different things. – Rost Oct 25 '12 at 13:58
  • @Rost I know. I still don't see what's wrong. An instantiation implies specialization, no? – Luchian Grigore Oct 25 '12 at 14:12
  • @LuchianGrigore This looks like terminology flaw. Specialization means alternative implementation, instantiation does not. – Rost Oct 25 '12 at 14:24
  • @Rost I can't think of a way (or, okay, reason) to have an instantiation without also having a specialization. – Luchian Grigore Oct 25 '12 at 14:26
  • @LuchianGrigore The reason is encapsulation. Just to move template function members implementation to cpp if that template will be used only with well-known set of types. Another reason is to restrict template usage with types you only allow. Non-general template to avoid copy-paste. – Rost Oct 25 '12 at 14:33
  • @Rost I don't see a difference (unless what you're saying is that the reason is to not have a visible interface for the template at all). Can you add an answer, I feel this is getting too long for comments. – Luchian Grigore Oct 25 '12 at 14:34
0

If you really don't like defining template functions in header files, you can define the functions in a separate source file and use explicit template instantiation to instantiate all the versions you use. Then you only need a forward declarations in your header file instead of the complete definition.

Dirk Holsopple
  • 8,731
  • 1
  • 24
  • 37
  • Where does the explicit template instantiation go? Header or source file? – Mark Ingram Oct 25 '12 at 12:59
  • @MarkIngram in the source file. The function will be in the object file produced from the source file, like a normal function, instead of being instantiated in every translation unit where it is used. – Dirk Holsopple Oct 25 '12 at 13:01