|
||||
|
Section 35:
|
[35.15] How can I avoid linker errors with my template classes? Updated!
[Recently updated due to C++11 syntax. Click here to go to the next FAQ in the "chain" of recent changes]
Tell your C++ compiler which instantiations to make while it is compiling your template class's .cpp file. (If you've already read the previous FAQ, this answer is completely symmetric with that one, so you can probably skip this answer.) As an example, consider the header file Foo.h which contains the following template class. Note that method Foo<T>::f() is inline and methods Foo<T>::g() and Foo<T>::h() are not.
// File "Foo.h"
template<typename T>
class Foo {
public:
void f();
void g();
void h();
};
template<typename T>
inline
void Foo<T>::f()
{
...
}
Now suppose file Foo.cpp actually defines the non-inline
methods Foo<T>::g() and Foo<T>::h():
// File "Foo.cpp"
#include <iostream>
#include "Foo.h"
template<typename T>
void Foo<T>::g()
{
std::cout << "Foo<T>::g()\n";
}
template<typename T>
void Foo<T>::h()
{
std::cout << "Foo<T>::h()\n";
}
Suppose file main.cpp uses this template class by creating a
Foo<int> and calling its methods:
// File "main.cpp"
#include "Foo.h"
int main()
{
Foo<int> x;
x.f();
x.g();
x.h();
...
}
If you compile and (try to) link these two .cpp files, most compilers will
generate linker errors. There are two solutions for this. The first
solution is to physically move the definition of the template functions into
the .h file, even if they are not inline functions. This solution may
(or may not!) cause significant code bloat, meaning your executable size may
increase dramatically (or, if your compiler is smart enough, may not; try it
and see).
The other solution is to leave the definition of the template function in the .cpp file and simply add the line template class Foo<int>; to that file: // File "Foo.cpp" #include <iostream> #include "Foo.h" ...definition of Foo<T>::f() is unchanged -- see above... ...definition of Foo<T>::g() is unchanged -- see above... template class Foo<int>;If you can't modify Foo.cpp, simply create a new .cpp file such as Foo-impl.cpp as follows: // File "Foo-impl.cpp" #include "Foo.cpp" template class Foo<int>;Notice that Foo-impl.cpp #includes a .cpp file, not a .h file. If that's confusing, click your heels twice, think of Kansas, and repeat after me, "I will do it anyway even though it's confusing." You can trust me on this one. But if you don't trust me or are simply curious, the rationale is given earlier. If you are using Comeau C++, you probably want to learn about the export keyword. |
|||