codekiddy codekiddy - 1 month ago 16
C++ Question

using extern template (C++11)

Figure 1: function templates



TemplHeader.h

template<typename T>
void f();


TemplCpp.cpp

template<typename T>
void f(){
//...
}
//explicit instantation
template void f<T>();


Main.cpp

#include "TemplHeader.h"
extern template void f<T>(); //is this correct?
int main() {
f<char>();
return 0;
}


Is this the correct way to use
extern template
, or do I use this keyword only for class templates as in Figure 2?

Figure 2: class templates



TemplHeader.h

template<typename T>
class foo {
T f();
};


TemplCpp.cpp

template<typename T>
void foo<T>::f() {
//...
}
//explicit instantation
template class foo<int>;


Main.cpp

#include "TemplHeader.h"
extern template class foo<int>();
int main() {
foo<int> test;
return 0;
}


I know it is good to put all of this in one header file, but if we instantiate templates with the same parameters in multiple files, then we got multiple same definitions and the compiler will remove them all (except one) to avoid errors. How do I use
extern template
? Can we use it only for classes, or can we use it for functions too?

Also, Figure 1 and Figure 2 may be expanded to a solution where templates are in a single header file . In that case, we need to use the
extern template
keyword to avoid multiple same instantations. Is this only for classes or functions too?

Answer

You should only use extern template to force the compiler to not instantiate a template when you know that it will be instantiated somewhere else. It is used to reduce compile time and reduce object file size.

For example:

// header.h

template<typename T>
void ReallyBigFunction()
{
    // Body
}

// source1.cpp

#include "header.h"
void something1()
{
    ReallyBigFunction<int>();
}

// source2.cpp

#include "header.h"
void something2()
{
    ReallyBigFunction<int>();
}

This will result in the following object files:

source1.o
    void something1()
    void ReallyBigFunction<int>()    // Compiled first time

source2.o
    void something2()
    void ReallyBigFunction<int>()    // Compiled second time

If both files are linked together, one void ReallyBigFunction<int>() will be discarded, resulting in wasted compile time and object file size.

To not waste compile time and object file size, there is an extern keyword which makes the compiler not compile a template function. You should use this if and only if you know it is used in the same binary somewhere else.

Changing source2.cpp to:

// source2.cpp

#include "header.h"
extern template ReallyBigFunction<int>();
void something2()
{
    ReallyBigFunction<int>();
}

Will result in the following object files:

source1.o
    void something1()
    void ReallyBigFunction<int>() // compiled just one time

source2.o
    void something2()
    // No ReallyBigFunction<int> here because of the extern

When both of these will be linked together, the second object file will just use the symbol from the first object file. No need for discard and no wasted compile time and object file size.

This should only be used within a project, like in times when you use a template like vector<int> multiple times, you should use extern in all but one source file.

This also applies to classes and function as one, and even template member functions.

Comments