Лично я предпочитаю поместить объявление (.h) в отдельный файл из определения (ваш файл .cc). Кроме того, я бы не стал включать файл .cc в файл .h. Методы в файле .h должны быть только встроенными.
Допустим, в вашем примере у вас также был файл заголовка (bar.h), который просто объявляет класс, содержащий элемент данных Foo.
Каждый раз, когда вы изменяете определение класса Foo, вы вызываете перекомпиляцию любого, кто включает bar.h, даже если они не заботятся об определении Foo. Тем не менее, bar.cpp - это, вероятно, место, где вы на самом деле реализуете материал, и этот файл ДОЛЖЕН включать реализацию вашего шаблона. Это кажется тривиальным в небольших проектах, но становится источником головной боли в больших проектах, которые постоянно перекомпилируют файлы без причины. Я видел, как люди бросали SSD и Incredibuild на вещи, которые можно было бы исправить с помощью простых форвардов и лучшего управления заголовками.
Лично я использую .imp.h для реализации моих шаблонов. Включение файлов cc или cpp мне кажется противным.
Например (извините за ошибки компиляции.;))
// foo.h
#ifndef foo_h
#define foo_h
template< typename T >
struct Foo
{
Foo( T value );
void print();
T _value;
};
#endif
//foo.imp.h
#ifndef foo_imp_h
#define foo_imp_h
#include "foo.h"
#include <iostream>
template< typename T >
Foo< T >::Foo( T value ) : _value( value ) {}
void Foo< T >::print() { std::cout << _value << std::endl; }
#endif
// bar.h
#ifndef bar_h
#define bar_h
#include "foo.h"
struct Bar {
Foo< int > _intFoo;
Foo< double > _doubleFoo;
void print();
};
#endif
// bar.cpp
#include "bar.h"
#include "foo.imp.h"
void Bar::print()
{
_intFoo.print();
_doubleFoo.print();
}
// foobar.cpp
#include "bar.h"
void foobar()
{
Bar bar;
bar.print();
}
Если бы определение foo было включено в foo.h или в него, bar.cpp и foobar.cpp были бы перекомпилированы. Так как только bar.cpp связан с реализацией Foo, разделение определения и объявления Foo на два файла и отсутствие foo.h, включающего в конце foo.imp.h, спасли меня от перекомпиляции foobar.cpp.
Это то, что происходит постоянно в проектах, и его очень легко избежать, следуя правилу .h / .imp.h, которое я объяснил выше. Причина, по которой вы никогда не видите этого в таких вещах, как STL или boost, заключается в том, что вы не изменяете эти файлы. Не имеет значения, находятся ли они в одном или двух файлах. Но в ваших собственных проектах вы будете постоянно изменять определения своих шаблонов, и именно так вы сокращаете время перекомпиляции.
Если вы уже знаете заранее, какие типы фактически будут использоваться с вашим шаблоном, то даже не беспокойтесь о файле .imp.h. Поместите все в .cpp и сделайте это в конце
// foo.cpp
// Implementation goes here.
// You might need to put something in front so that it gets exported from your DLL,
// depening on the platform
template class foo< int >;
template class foo< double >;