extern template
When you are compiling a header full of template in different places and they share the same instantation parameters, you’ll waste a lot of time compiling them. Luckily, c++11 introduce “extern template” to solve this problem.
First, you need to add the following code to every compilation unit to force the compiler to not instantiate the template immediately.
//it's just like the specialization of a function but with no template paramter list
extern template ret_t optional classname:: func_name<specific_type>(parms ...);
Then, you need to create a .cc file to store the instantation of these functions.
//some-name.cc
#include <the-template-header.h>//it can be included in other #include stype\
template ret_t optional classname:: func_name<specific_type>(parms ...);
Then use compiler-name -std=c++11 -c -probably-other-parms some-name.cc
, you will get the PID code of these templates,
and now you can use the samecommand (-probably-other-parms doesn’t need to be the ssame) to compile other .cc files that use
these templates and link them togther. Bingo, they work!
But how about writing a template header and then put some rather frequent used instantiation into a .cc file?
I write the following test code to illustrate how to use it:
//extern_template.h
template <class A>
struct wrapper {
A object;
A& getA() noexcept { return object; }
};
extern template int& wrapper<int>::getA() noexcept;
template <class T> void print(const T &val) { std::cout << val << std::endl; }
extern template void print<int>(const int&);
//extern_template.cc
#include "extern_template.h"
template int& wrapper<int>::getA() noexcept;
template void print<int>(const int&);
//main.cc
#include "extern_template.h"
int main() {
wrapper<int> A{1};
std::cout << A.getA() << wrapper<char>{'s'}.getA() << std::endl;
print(int{10});
}
Disassembly of section .text._ZN7wrapperIiE4getAEv:
0000000000000000 <_ZN7wrapperIiE4getAEv>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 89 7d f8 mov %rdi,-0x8(%rbp)
8: 48 8b 45 f8 mov -0x8(%rbp),%rax
c: 5d pop %rbp
d: c3 retq
Disassembly of section .text._Z5printIiEvRKT_:
0000000000000000 <_Z5printIiEvRKT_>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 10 sub $0x10,%rsp
8: 48 b8 00 00 00 00 00 movabs $0x0,%rax
f: 00 00 00
12: 48 89 7d f8 mov %rdi,-0x8(%rbp)
16: 48 8b 7d f8 mov -0x8(%rbp),%rdi
1a: 8b 37 mov (%rdi),%esi
1c: 48 89 c7 mov %rax,%rdi
1f: e8 00 00 00 00 callq 24 <_Z5printIiEvRKT_+0x24>
24: 48 be 00 00 00 00 00 movabs $0x0,%rsi
2b: 00 00 00
2e: 48 89 c7 mov %rax,%rdi
31: e8 00 00 00 00 callq 36 <_Z5printIiEvRKT_+0x36>
36: 48 89 45 f0 mov %rax,-0x10(%rbp)
3a: 48 83 c4 10 add $0x10,%rsp
3e: 5d pop %rbp
3f: c3 retq
It works! And the a.out compiled from main.cc can output:
1s
10