Аспект C ++, который меня периодически расстраивает, - это выбор места для шаблонов между заголовочными файлами (традиционно описывающими интерфейс) и файлами реализации (.cpp).Шаблоны часто должны идти в заголовке, раскрывая реализацию и иногда добавляя дополнительные заголовки, которые ранее нужно было только включить в файл .cpp.Недавно я столкнулся с этой проблемой еще раз, и ее упрощенный пример показан ниже.
#include <iostream> // for ~Counter() and countAndPrint()
class Counter
{
unsigned int count_;
public:
Counter() : count_(0) {}
virtual ~Counter();
template<class T>
void
countAndPrint(const T&a);
};
Counter::~Counter() {
std::cout << "total count=" << count_ << "\n";
}
template<class T>
void
Counter::countAndPrint(const T&a) {
++count_;
std::cout << "counted: "<< a << "\n";
}
// Simple example class to use with Counter::countAndPrint
class IntPair {
int a_;
int b_;
public:
IntPair(int a, int b) : a_(a), b_(b) {}
friend std::ostream &
operator<<(std::ostream &o, const IntPair &ip) {
return o << "(" << ip.a_ << "," << ip.b_ << ")";
}
};
int main() {
Counter ex;
int i = 5;
ex.countAndPrint(i);
double d=3.2;
ex.countAndPrint(d);
IntPair ip(2,4);
ex.countAndPrint(ip);
}
Обратите внимание, что я намерен использовать свой фактический класс в качестве базового класса, следовательно, виртуальный деструктор;Я сомневаюсь, что это имеет значение, но я оставил это в Counter на всякий случай.Результат, полученный в результате вышеописанного:
counted: 5
counted: 3.2
counted: (2,4)
total count=3
Теперь объявление класса Counter
может быть помещено в заголовочный файл (например, counter.h).Я могу поместить реализацию dtor, которая требует iostream, в counter.cpp.Но что делать с шаблоном функции-члена countAndPrint()
, который также использует iostream?Он не используется в counter.cpp, поскольку его необходимо создавать вне скомпилированного counter.o.Но добавление его в counter.h означает, что все, в том числе и counter.h, также включает iostream, что кажется неправильным (и я признаю, что мне, возможно, придется преодолеть это отвращение).Я мог бы также поместить код шаблона в отдельный файл (counter.t?), Но это было бы немного удивительно для других пользователей кода. Lakos на самом деле не так важен, как хотелось бы, а C ++ FAQ не подходит для лучшей практики.Итак, что мне нужно:
- Есть ли какие-нибудь альтернативы для разделения кода на те, что я предложил?
- на практике, что работает лучше всего?