Почему я получаю отсутствующие символы для явной специализации шаблона в статической библиотеке?

Если я скомпилирую следующий код:

//
// g++ static.cpp -o static.o
// ar rcs libstatic.a static.o
//
#include <iostream>

template < typename T >
struct TemplatedClass
{
  void Test( T value )
  {
    std::cout << "Foobar was: " << value << std::endl;
  }
};

template struct TemplatedClass < long >;

Я получаю статическую библиотеку, и если я запускаю nm в библиотеке, я получаю следующие результаты:

testcase% nm libstatic.a | c++filt | grep TemplatedClass
0000000000000207 s global constructors keyed to _ZN14TemplatedClassIlE4TestEl
0000000000000300 s global constructors keyed to _ZN14TemplatedClassIlE4TestEl.eh
0000000000000118 T TemplatedClass<long>::Test(long)
00000000000002a0 S __ZN14TemplatedClassIlE4TestEl.eh

Однако если я скомпилирую следующий код, который будет таким же, за исключением того, что я добавил явную специализацию шаблонного класса...

//
// g++ static.cpp -o static.o
// ar rcs libstatic.a static.o
//
#include <iostream>

template < typename T >
struct TemplatedClass
{
  void Test( T value )
  {
    std::cout << "Foobar was: " << value << std::endl;
  }
};

template <>
struct TemplatedClass < long >
{
  void Test( long value )
  {
     std::cout << "Value was: " << value << std::endl;
  }
}; 

template struct TemplatedClass < long >;

... и повторите ту же команду:

testcase% nm libstatic.a | c++filt| grep TemplatedClass
testcase% 

Я не получаю совпадающих символов. По какой-то причине компилятор не создает экземпляр шаблона, хотя я явно просил его об этом.

Может кто-нибудь объяснить мне, что здесь происходит?


person jkp    schedule 21.10.2010    source источник


Ответы (1)


У вас есть определения функций-членов в определениях классов (шаблонов). Это приводит к тому, что функции-члены (шаблоны) становятся inline. Это не так важно для функции-члена класса-шаблона, поскольку ее требования к компоновке в большей степени определяются характером ее реализации.

Но во втором примере функция-член void TemplatedClass<long>::Test(long) не является шаблоном функции и по-прежнему является inline. Таким образом, компилятору не требуется ничего делать с ним, если он не используется, и он должен быть определен во всех файлах, где он используется. Поскольку вы утверждаете, что это находится в файле static.cpp, встроенная функция, вероятно, не то, что вам нужно.

Я думаю, вы получите результаты, более похожие на ожидаемые, если вы измените что-то на:

template <>
struct TemplatedClass < long >
{
  void Test( long value );
};

void TemplatedClass<long>::Test( long value )
{
  std::cout << "Value was: " << value << std::endl;
}

И когда вы определяете явную специализацию, вам, вероятно, также не требуется явное создание экземпляра (если это вообще законно).

person aschepler    schedule 21.10.2010
comment
Вы специализируете весь класс (и это действительно хорошо работает). Но что, если кто-то хочет специализировать только подмножество из всех методов универсального класса? Когда я использую описанный синтаксис, я не могу получить доступ к остальным неспециализированным методам. - person Spook; 03.01.2012
comment
Призрак, это так задумано. Если вы специализируетесь, вы начинаете с нуля. Я бы порекомендовал получить от общего шаблонного базового класса специализированные и неспециализированные шаблоны. - person Daniel Albuschat; 28.06.2014
comment
Связанный: stackoverflow.com/questions/495021/ - person Asher; 11.06.2015