Внутрянка инстанциаций шаблонов



Хочу в этом небольшом посте в явном виде продемонстрировать вам, что значит определение шаблона и его явная/неявная инстанциация. Сразу говорю, что буду использовать gcc в качестве компилятора.



Возьмем тот же пример с кораблем и оставим от него только хэдэр и сорец:



// ship.hpp

template<typename T>

struct Ship

{

// contain some fields

void TurnShip(T command);

};



// ship.cpp

#include "ship.hpp"

#include <string>



template <class T>

void Ship<T>::TurnShip(T command) {/* do stuff using command */}







Сейчас в единице трансляции, соответствующей ship.cpp, есть только объявление и определение шаблона, больше ничего. Это значит, что никакого кода для этого юнита генерироваться не будет.



Проверим это с помощью утилитки nm, которая показывает символы бинарника. Скомпилируем ship.cpp в объектный файл и посмотрим, какие там символы есть внутри:



nm ship.o



//Output

ship.o: no symbols







Как говорят математики: ЧТД и точка!



Теперь проверим неявную инстанциацию. Добавим в ship.cpp функцию:



void foo() {

Ship<std::string> ship{};

ship.TurnShip(std::string{"Turn upside down"});

}







Посмотрим теперь на символы этого юнита. Помимо всего прочего побочного непотребства, получим следующее:



nm ship.o



//Output

0000000000000000 T __Z3foov

0000000000000060 T __ZN4ShipINSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEE8TurnShipES6_





Теперь мы имеем скомпилированную функцию foo и метод TurnShip класса Ship параметризованного строкой.



Для явной инстанциации уберем из ship.cpp функцию foo и добавим строчку:



template struct Ship<std::string>;





и посмотрим на символы:



nm ship.o



//Output

0000000000000000 T __ZN4ShipINSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEE8TurnShipES6_







Как и ожидалось в принципе.



Вот поэтому-то при использовании подхода разделения шаблона на объявление в хэдэре и определение в сорце без явной инстанциации будет ошибка линковки. В единице трансляции, соответствующей определению шаблона, не будет никакого кода. Единицы трансляции на этапе компиляции не обмениваются информацией, поэтому компилятор не сможет инстанцировать шаблон на этом этапе. А на этапе линковки уже поздно смотреть на определение шаблона, потому что его просто не будет. Текст уберется, а кода никакого сгенерировано не будет. Как-то так.



Я не просто так вам это все рассказываю. Это нужно для понимания дальнейших постов.



Don't rely on words, check them. Stay cool.



#cppcore #template #compiler