Ошибка компоновщика при использовании внешнего шаблона - PullRequest
5 голосов
/ 19 декабря 2011

У меня есть рабочий код с шаблоном. Подобно stl :: string, я в основном использую свой шаблон с одним параметром для нескольких модулей компиляции. Чтобы сэкономить время, я пытаюсь использовать externintiation . Однако изменение строк следующим образом приводит к ошибке. Как правильно это сделать? (P.S. Компиляция на gcc с флагом c ++ 0x)

typedef myTemplate_base<commonType> myTemplate;
extern template class myTemplate_base<commonType>; //using "extern template myTemplate" wont work

Я добавил в проект дополнительный файл cpp со следующим:

template class myTemplate_base<commonType>;

Компоновщик выводит сообщение об ошибке (в качестве источника ошибки указывается строка первого экземпляра объекта (myTemplate someVar;) в основном файле):

неопределенная ссылка 'myTemplate_base :: ~ myTemplate_base ()'

Однако этот тип относится к классу со следующим определением ~myTemplate() = default;

Редактировать: Если у вас есть более подходящее название, пожалуйста, прокомментируйте, чтобы правильные люди взглянули на это

Edit2: Есть забавная вещь: добавление template class myTemplate_base<commonType> значительно увеличивает размер исполняемого файла (+ 100k на двоичном коде 450k), даже если шаблон используется в основном (для компиляции у меня есть) комментировать extern часть). Это намекает на то, что компоновщик сохраняет две реализации шаблона с одной и той же реализацией / me, что-то упускает

1 Ответ

5 голосов
/ 20 декабря 2011

Вы нашли ошибку компилятора.Я воспроизвел это с g++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1.Обходной путь - оставить деструктор неявным образом по умолчанию.Ошибка компоновщика возникает только тогда, когда деструктор явно помечает его как значение по умолчанию (= default).

В любом случае деструктор никогда не создается с внешним шаблоном.Отмечая класс шаблона как внешний, компилятор отмечает, что любые необходимые символы являются внешними.За исключением деструктора, он все еще определен в файле.Похоже, что добавление = default с шаблоном extern приводит к тому, что компилятор думает, что деструктор будет определен в другом месте.

Раздувание кода вызвано шаблоном extern.Компилятор только создает экземпляры методов класса шаблона, которые фактически используются.Это обычно намного меньше, чем число, которое определено.Когда вы используете принудительное создание экземпляра класса с extern template, компилятор генерирует код для всех методов (кроме деструктора, как вы только что обнаружили).


g++ -c -std=c++0x main.cpp
g++ -c -std=c++0x extern.cpp
g++ main.o extern.o

header.hpp

#pragma once

#include <iostream>
#include <string>
#include <typeinfo>

template< typename T >
class Foo
{
public:
   Foo( void ) :
      m_name( typeid(T).name() ),
      m_t( T() )
   { }

   // add or remove this to cause the error
   ~Foo( void ) = default;

   void printer( void )
   {
      std::cout << m_name << std::endl;
   }

   T returner( void )
   {
      return m_t;;
   }

private:
   std::string m_name;
   T m_t;
};

extern template class Foo<int>;

extern.cpp

#include "header.hpp"

template class Foo<int>;

main.cpp

#include "header.hpp"

int main()
{
   Foo<int> fi;
   fi.printer();

   Foo<float> ff;
   ff.printer();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...