Take this code, for example:
/*
* foo.h
*
* Created on: Nov 5, 2011
* Author: AutoBotAM
*/
#ifndef FOO_H_
#define FOO_H_
template<typename Type>
class Foo
{
public:
void Bar(Type object);
};
#endif /* FOO_H_ */
.
/*
* foo.cpp
*
* Created on: Nov 5, 2011
* Author: AutoBotAM
*/
#include <iostream>
using namespace std;
#include "foo.h"
template<typename Type>
void Foo<Type>::Bar(Type object)
{
cout << object;
}
.
/*
* main.cpp
*
* Created on: Oct 15, 2011
* Author: AutoBotAM
*/
#include <iostream>
using namespace std;
#include "foo.h"
Foo<int> foo;
int main()
{
cout << "The year is ";
foo.Bar(2011);
return 0;
}
This is how I usually go about declaring non-template classes. Unfortunately this code results in the error ../src/main.cpp:18: undefined reference to 'Foo<int>::Bar(int)' (in MinGW). I did some reading, and it turns out you have to declare template classes in the same translation unit, like so:
/*
* foo.h
*
* Created on: Nov 5, 2011
* Author: AutoBotAM
*/
#ifndef FOO_H_
#define FOO_H_
template<typename Type>
class Foo
{
public:
void Bar(Type object)
{
cout << object;
}
};
#endif /* FOO_H_ */
My big question is, why do you have to do this? I could imagine a few pitfalls in development with this scheme. For example, imagine we had 50 translation units #including foo.h, and we make a change to void Foo::Bar(Type). Since Bar is in the header file, we’ll have to wait for all 50 of those translation units to compile before we get any results. If we had Bar working in foo.cpp separately, we would only have to wait for 1 translation unit to compile. Are there any ways to overcome this issue?
Thanks for any advice!
Templates are not types. They are only templates. They only become a type when they are instantiated (with a complete set of parameters).
Compilation requires that all necessary type definitions be available at compile time. Moreover, linking requires that all necessary function definitions, including member functions, exist in some translation unit (with inlining providing the usual exemption to the one-definition-rule).
If you put all this together, it follows almost automatically that all template member function definition of a template class must be available for every used template instantiation at some point in the compilation process.
On the other hand, consider the following setup:
If you compile the implementation file, it doesn’t contain any code, since there is no template instance to be compiled. A user of the header file may instantiate
Foo<int>, but the body of the class never gets instantiated in any TU, so you get a linker error when piecing together the program.It may help to think of templates as a code generation tool rather than actual code, at least for the purpose of compilation.