A detailed explanation is available at http://www.parashift.com/c++-faq-lite/templates.html
[35.12] Why can't I separate the definition of my template from its declaration and put it in a .cpp file?
If you want to know how to fix this situation, read the following two frequently asked questions. But to understand why this is so, first accept the following facts:
- A template is not a class or function. A template is a “template” that the compiler uses to generate a family of classes or functions.
- In order for the compiler to generate code, it must see both the definition of the template (and not just the declaration), as well as the specific types / everything that is used to "populate" the template. For example, if you are trying to use Foo, the compiler should see both the Foo pattern and the fact that you are trying to create a specific Foo.
- Your compiler probably does not remember the details of one .cpp file when it compiles another .cpp file. It is possible, but most of them do not, and if you read this FAQ, it almost certainly does not. BTW is called a "separate compilation model."
Now, based on these facts, here is an example that shows why everything is as it is. Suppose you have a Foo template like this:
template<typename T> class Foo { public: Foo(); void someMethod(T x); private: T x; };
Along with similar definitions for member functions:
template<typename T> Foo<T>::Foo() { ... } template<typename T> void Foo<T>::someMethod(T x) { ... }
Now suppose you have the code in the Bar.cpp file that Foo uses:
//Bar.cpp
void blah_blah_blah() { ... Foo<int> f; f.someMethod(5); ... }
Clearly, somewhere, someone will have to use the “template” to define the constructor and to define someMethod () and create instances when T is actually int. But if you entered the definition of the constructor and someMethod () in the Foo.cpp file, the compiler will see the template code when compiling Foo.cpp, and he will see Foo when he compiles Bar.cpp, but never when he saw the template code, and foo. Thus, by rule number 2 above, he will never be able to generate code for Foo :: someMethod ().
Note to experts: I obviously made a few simplifications above. This was intentional, so please do not complain too loudly. If you know the difference between a .cpp file and a compilation unit, the difference between a class template and a template class, and the fact that templates are really not just famous macros, then do not complain: this specific question / answer was not directed to you. I simplified everything so that newcomers “understand”, even if it offends some experts.
[35.13] How to avoid linker errors with my template functions?
Tell your C ++ compiler which instances should run when it compiles your .cpp file.
As an example, consider the header file foo.h, which contains the following template function declaration:
// File "foo.h"
template<typename T> extern void foo();
Now suppose the foo.cpp file actually defines this template function:
// File "foo.cpp"
#include <iostream> #include "foo.h" template<typename T> void foo() { std::cout << "Here I am!\n"; }
Suppose the main.cpp file uses this template function by calling foo ():
// File "main.cpp"
#include "foo.h" int main() { foo<int>(); ... }
If you compile and (try) linking these two .cpp files, most compilers will generate linker errors. There are three solutions for this. The first solution is to physically move the definition of the template function to the .h file, even if it is not a built-in function. This solution may (or may not be!) Cause significant bloating of code, which means that the size of the executable file can increase dramatically (or, if your compiler is smart enough, cannot, try it and see).
Another solution is to leave the template function definition in the .cpp file and just add the void foo () line template; to this file:
// File "foo.cpp"
#include <iostream> #include "foo.h" template<typename T> void foo() { std::cout << "Here I am!\n"; } template void foo<int>();
If you cannot modify foo.cpp, simply create a new .cpp file, for example foo-impl.cpp, as follows:
// File "foo-impl.cpp"
#include "foo.cpp" template void foo<int>();
Note that foo-impl.cpp # includes the .cpp file, not the .h file.