На днях напоролся на проблему multiple definition при попытке компиляции файлов с шаблонами.
Схема проекта выглядела следующим образом:
Всё было хорошо до тех пор, пока не появился проектик из двух cpp файлов, каждый из которых подключал файл header.h.
В этом можно убедиться двумя способами: 1) просмотрев имена функций в .o файлах с помощью unix-утилиты nm ; 2) добавив флаг компилятора -save-temps компилятора gcc и просмотрев получившиеся .ii файлы.
Поскольку тела шаблонных методов/функций должны быть известны на этапе компиляции конкретной цели (.o файла), т.е., при компиляции cpp-файла, файлы с такими телами нужно подключить с помощью #include. Но теперь уже из того файла, где реально нужно определение функции/метода, а не только объявление. Например,
Схема проекта выглядела следующим образом:
// file header.h
#ifndef HEADER_H
#define HEADER_H
template< class T >
class TemplatedClass
{
TemplatedClass( ParamType param );
};
#include "implementation.inl"
#endif
// end of file header.h
// file implementation.inl
#ifndef IMPLEMENTATION_INL#define IMPLEMENTATION_INL
template<>
TemplatedClass::TemplatedClass<SpecialType>(ParamType param)
{
// code here
}
#endif// end of file implementation.inl
Всё было хорошо до тех пор, пока не появился проектик из двух cpp файлов, каждый из которых подключал файл header.h.
Вполне закономерно, в каждом .o файле этих .cpp файлов оказалось тело конструктора TemplatedClass::TemplatedClass<SpecialType>(ParamType param), что и привело к ошибке компоновки.// file 1.cpp#include <header.h>...// end of file 1.cpp// file 2.cpp#include <header.h>...// end of file 2.cpp
В этом можно убедиться двумя способами: 1) просмотрев имена функций в .o файлах с помощью unix-утилиты nm ; 2) добавив флаг компилятора -save-temps компилятора gcc и просмотрев получившиеся .ii файлы.
Поскольку тела шаблонных методов/функций должны быть известны на этапе компиляции конкретной цели (.o файла), т.е., при компиляции cpp-файла, файлы с такими телами нужно подключить с помощью #include. Но теперь уже из того файла, где реально нужно определение функции/метода, а не только объявление. Например,
// file header.h
#ifndef HEADER_H
#define HEADER_H
template< class T >
class TemplatedClass
{
TemplatedClass( ParamType param );
};
#include "implementation.inl"#endif
// end of file header.h
// file implementation.inl
#ifndef IMPLEMENTATION_INL#define IMPLEMENTATION_INL
template<>
TemplatedClass::TemplatedClass<SpecialType>(ParamType param)
{
// code here
}
#endif// end of file implementation.inl
// file 1.cpp
#include <header.h>
...
// end of file 1.cpp
// file 2.cppP.S. Возможно, при таких ошибках стоит пересмотреть состав заголовочных файлов - может быть, его можно разделить на несколько самостоятельных (лично у себя нашёл такой недочёт).
#include <header.h>
#include <implementation.inl>
...
// end of file 2.cpp
Комментариев нет:
Отправить комментарий