Действительно ли мудро иметь, включают защиту вокруг шаблонных классов?
Разве шаблонные классы, как предполагается, не повторно анализируются каждый раз, когда Вы ссылаетесь на них с другой реализацией?
N.B В Visual C++ 2008 я не получаю ошибок при объединении двух...
Предполагается, что определения шаблонов разбираются один раз (и такие вещи, как двухфазный поиск имени, здесь для того, чтобы как можно больше ошибок можно было выдать сразу, без инстанцирования). Инстанцирование происходит с использованием внутренней структуры данных, построенной на тот момент.
Определения шаблонов обычно (т.е. если вы не используете export
или не делаете что-то особенное) находятся в заголовочных файлах, которые должны иметь свой include guard. Добавлять его для определения шаблона бесполезно, но не вредно.
Вам нужна охрана. Рассмотрим этот код:
// this is t.h
template <typename T>
void f( T t ) {
}
// this is t.cpp
#include "t.h"
#include "t.h"
int main() {
f( 1 );
}
Это дает ошибку:
t.h:2: error: redefinition of 'template<class T> void f(T)'
t.h:2: error: 'template<class T> void f(T)' previously declared here
Кроме того, заголовки, которые содержат шаблоны, обычно также содержат не шаблонный код.
Короткий ответ: Каждый блок, который вы планируете включать более одного раза с какими-либо определениями, должен иметь защиту заголовка. То есть с шаблонами или без них.
Чтобы ответить на ваш первый вопрос: Да, это разумно, и обязательно, иметь включающие защиты вокруг шаблонных классов. Или, более строго, вокруг всего содержимого каждого заголовочного файла.
Это способ подчиниться правилу одного определения, когда у вас есть материал в заголовочных файлах, так чтобы он был общим и при этом безопасным. Могут существовать другие заголовочные файлы, включающие ваш. Когда компилятор компилирует файл модуля, он может увидеть #include
вашего заголовочного файла много раз, но защита включается во второй и последующие разы, чтобы убедиться, что компилятор видит содержимое только один раз.
Неважно, что компилятор ничего не разбирает; это его работа. Вы просто должны предоставить содержимое один раз, после чего компилятор уже видел его и может обращаться к нему столько раз, сколько ему нужно.