Хотя стандарт C++ не имеет такого требования, некоторые компиляторы требуют, чтобы все функциональные шаблоны были доступны в каждой единицы перевода, в которой он используется. Фактически для этих компиляторов должны быть доступны тела функций шаблона в файле заголовка. Повторить: это означает, что эти компиляторы не позволят их определять в файлах без заголовка, таких как .cpp-файлы.Чтобы уточнить, в C++ ESE это означает, что это:
// ORIGINAL version of xyz.h
template <typename T>
struct xyz
{
xyz();
~xyz();
};
НЕ буду удовлетворен этими определениями CT и dtors:
// ORIGINAL version of xyz.cpp
#include "xyz.h"
template <typename T>
xyz<T>::xyz() {}
template <typename T>
xyz<T>::~xyz() {}
, потому что с помощью его:
// main.cpp
#include "xyz.h"
int main()
{
xyz<int> xyzint;
return 0;
}
приведет к ошибке. Например, с Comeau C++ вы получите:
C:\export>como xyz.cpp main.cpp
C++'ing xyz.cpp...
Comeau C/C++ 4.3.4.1 (May 29 2004 23:08:11) for MS_WINDOWS_x86
Copyright 1988-2004 Comeau Computing. All rights reserved.
MODE:non-strict warnings microsoft C++
C++'ing main.cpp...
Comeau C/C++ 4.3.4.1 (May 29 2004 23:08:11) for MS_WINDOWS_x86
Copyright 1988-2004 Comeau Computing. All rights reserved.
MODE:non-strict warnings microsoft C++
main.obj : error LNK2001: unresolved external symbol xyz<T1>::~xyz<int>() [with T1=int]
main.obj : error LNK2019: unresolved external symbol xyz<T1>::xyz<int>() [with T1=int] referenced in function _main
aout.exe : fatal error LNK1120: 2 unresolved externals
, потому что нет никакой пользы от CTOR или dtor в xyz.cpp, следовательно, нет конкретизации, что должно произойти оттуда. К лучшему или к худшему, так работают шаблоны.
Один из способов этого - явно запросить экземпляр xyz
, в этом примере xyz<int>
. В грубой силы усилий, это может быть добавлено к xyz.cpp путем добавления этой строки в конце его:
template xyz<int>;
, который запрашивает, что (все) xyz<int>
быть создан. Однако это не в том месте, потому что это означает, что каждый раз, когда возникает новый тип xyz, необходимо изменить файл реализации xyz.cpp. Менее навязчивый способ избежать этого файла, чтобы создать другой:
// xyztir.cpp
#include "xyz.cpp" // .cpp file!!!, not .h file!!
template xyz<int>;
Это еще несколько болезненным, потому что она по-прежнему требует ручного вмешательства каждый новый хуг принесенное вперед. В нетривиальной программе это может быть необоснованным спросом на обслуживание.
Так вместо этого, другой способ решения этой проблемы является #include "xyz.cpp"
в конце xyz.h:
// xyz.h
// ... previous content of xyz.h ...
#include "xyz.cpp"
Вы, конечно, может буквально принести (вырезать и вставить его) содержимое xyz.cpp к конец xyz.h, следовательно, избавиться от xyz.cpp; это вопрос организации файлов, и в конечном итоге результаты предварительной обработки будут одинаковыми, поскольку тела ctor и dtor будут в заголовке и, следовательно, включены в любой запрос компиляции, так как это будет использовать соответствующий заголовок. В любом случае, это имеет побочный эффект, который теперь каждый шаблон находится в вашем файле заголовка. Это может замедлить компиляцию, и это может привести к раздуванию кода. Один из способов приблизиться к последнему - объявить рассматриваемые функции, в этом случае ctor и dtor, как inline, так что это потребует от вас изменить xyz.cpp в примере выполнения.
В некоторых случаях некоторые компиляторы также требуют, чтобы некоторые функции были определены внутри класса, а не за пределами одного, поэтому в случае этих компиляторов необходимо будет изменить настройку выше. Обратите внимание, что это проблема компилятора, а не стандарт Standard C++, поэтому не все компиляторы требуют этого. Например, Comeau C++ не делает этого и не должен. За дополнительной информацией о нашей текущей настройке обращайтесь к http://www.comeaucomputing.com/4.0/docs/userman/ati.html. Короче говоря, Comeau C++ поддерживает многие модели, в том числе те, которые близки к тому, что намерения ключевого слова экспорта (как расширение), а также даже поддерживают сам экспорт.
И, наконец, обратите внимание, что ключевое слово экспорта C++ предназначено для устранения исходного вопроса. Однако в настоящее время Comeau C++ является единственным компилятором, который публикуется для поддержки экспорта. См. http://www.comeaucomputing.com/4.0/docs/userman/export.html и http://www.comeaucomputing.com/4.3.0/minor/win95+/43stuff.txt для некоторых деталей. Надеюсь, что другие компиляторы достигнут соответствия стандарту C++, эта ситуация изменится.В приведенном выше примере, с помощью экспорта означает возврат к исходному коду, который произвел ошибки компоновщика, и внесение изменений: объявить шаблон в xyz.h с экспортом ключевым словом:
// xyz.h
export
// ... ORIGINAL contents of xyz.h ...
В CTOR и dtor в А. cpp будет экспортироваться просто в силу #includeing xyz.h, который он уже делает. Таким образом, в этом случае вам не нужен xyztir.cpp или запрос на создание экземпляра в конце xyz.cpp, и вам не нужно вводить ctor или dtor вручную в xyz.h. В командной строке, показанной ранее, возможно, что компилятор сделает все за вас автоматически.
Это не слишком новое, ему 10 лет, как и другие функции в стандарте C++ 98! : D Более того, для его реализации требуется редизайн компилятора, и они не считают, что это того стоит. – KTC 2008-11-11 08:06:40
Это делает компоновщика сложным, особенно если вы хотите сделать много умной оптимизации всей программы на этапе ссылки. – 2008-11-11 19:39:04