template implementations in multiple sources
-
20-06-2021 - |
Pregunta
I'm using the following pattern to keep template declarations and implementations separate:
decl.h (declaration)
template <typename T>
struct Foo
{
void DoIt();
}
impl.cpp (implementation)
template <typename T>
void Foo<T>::DoIt() { // impl code
};
template class Foo<int>;
template class Foo<float>;
Now i want to add a new method to Foo, but the impl.cpp file is already huge, so i want to move it to a separate file impl2.cpp;
decl.h (declaration)
template <typename T>
struct Foo
{
void DoIt();
void RemoveIt();
}
impl.cpp (implementation)
template <typename T>
void Foo<T>::DoIt() { // impl code
};
template class Foo<int>;
template class Foo<float>;
impl2.cpp (implementation)
template <typename T>
void Foo<T>::RemoveIt() { // impl code
};
template class Foo<int>;
template class Foo<float>;
the main concern here are the duplicate instantiations, how do i avoid those?
Solución
Do as follows:
- Move definition of
Foo<T>::DoIt()
to some header file named ImplDoIt.h (not necessarily in the same directory as decl.h) - Same for
Foo<T>::RemoveIt()
- ImplRemoveIt.h - Include in your impl.cpp all these header files and instantiate the templates.
Otros consejos
You need to include the implementations for general template argument T
into the header and the explicit instantiations for int
and float
in a source file.
// decl.h
template <typename T>
struct Foo
{
void DoIt();
void RemoveIt();
}
#include "impl1.ipp"
#include "impl2.ipp"
// impl1.ipp
template <typename T>
void Foo<T>::DoIt() { // impl code
};
// impl2.ipp
template <typename T>
void Foo<T>::RemoveIt() { // impl code
};
// inst.cpp
#include "decl.h"
template class Foo<int>; // explicit instantiation goes in source file
template class Foo<float>; // explicit instantiation goes in source file
// main.cpp
#include "decl.h"
int main()
{
// call with concrete template arguments
Foo<int>::DoIt();
Foo<float>::RemoveIt();
}
Why? Because DoIt
and RemoveIt
are functions templates, not functions, and they cannot be compiled before seeing the template T
being passed to them. So all clients of Foo
need to include not only your header but also your implementation files. The most convenient way is to let the header include the implementations. That's why I renamed them to .ipp
.