Extern Templates with Separate Files
What are the implications of using extern
templates with separate implementation files?
Using extern templates with separate implementation files can be a powerful technique for reducing compile times in large C++ projects. Let's explore the implications and how to use this feature effectively.
What are Extern Templates?
Introduced in C++11, extern templates allow you to declare that a template instantiation exists somewhere else in the program, preventing the compiler from generating code for that instantiation in the current translation unit.
Basic Usage
Here's how you might use extern templates with separate files:
// MyTemplate.h
#pragma once
template <typename T>
class MyTemplate {
public:
void foo();
};
// Declare extern template
extern template class MyTemplate<int>;
// MyTemplate.cpp
#include <iostream>
#include "MyTemplate.h"
template <typename T>
void MyTemplate<T>::foo() {
std::cout << "MyTemplate::foo()\n";
}
// Explicit instantiation
template class MyTemplate<int>;
// main.cpp
#include "MyTemplate.h"
int main() {
MyTemplate<int> obj;
obj.foo();
}
MyTemplate::foo()
Implications
- Reduced Compile Time: The main benefit is faster compilation. The compiler won't generate code for
MyTemplate<int>
in every translation unit that includes "MyTemplate.h". - Linker Dependency: You must ensure that the translation unit with the explicit instantiation is linked into your program. If not, you'll get linker errors.
- Careful Management: You need to manually manage which instantiations are extern and which are explicitly instantiated.
- Limited to Specific Types: You need to declare extern templates for each type you want to use this way.
- Potential for ODR Violations: If you accidentally have multiple definitions of the same template instantiation, you might violate the One Definition Rule.
Best Practices
- Use extern templates for frequently used template instantiations in large projects.
- Keep a centralized location (like a .cpp file) for all your explicit instantiations.
- Be consistent with your use of extern templates across your project.
- Consider using a tool or script to manage extern template declarations and instantiations in large projects.
Multiple Types
In this example, we instantiate our template for multiple sets of template arguments:
// MyTemplate.h
#pragma once
template <typename T>
class MyTemplate {
public:
void foo();
};
extern template class MyTemplate<int>;
extern template class MyTemplate<double>;
// MyTemplate.cpp
#include <iostream>
#include "MyTemplate.h"
template <typename T>
void MyTemplate<T>::foo() {
std::cout << "MyTemplate::foo() with "
<< typeid(T).name() << "\n";
}
template class MyTemplate<int>;
template class MyTemplate<double>;
Remember, while extern templates can significantly reduce compile times in large projects, they also add complexity to your code organization.
Use them judiciously, and always measure the impact on your specific project to ensure they're providing the desired benefits.
Templates and Header Files
Learn how to separate class templates into declarations and definitions while avoiding common linker errors