Не всегда инстанциация шаблона нужна для работы программы
Возьмем пример из прошлого поста, объединим в хэдэре объявление шаблона с его определением и выкинем ship.cpp. И попробуем скомпилировать только main.cpp.
И неожиданно, все компилируется и выводится единичка. Почему так? Мы ведь почти ничего не поменяли даже просто нагло и беспардонно выкинули так нам необходимую единицу трансляции с явным инстанированием. Как это работает?
Дело в том, что любой метод, определенный внутри описания класса, неявно помечается inline. А на инлайн сущности не работает эффект подавления неявной специализации. Стандарт вот что говорит об этом:
Кажется, тут можно такую цепочку мыслей провести: компилятору запрещается делать неявную инстанциацию строкового корабля. Но он ее может и не делать, а просто встроить вызов метода этой инстанциации внутрь функции main и дело в шляпе! И ничего не нарушили и все работает.
Естественно, на это полагаться нельзя, потому что не любой метод может быть встроен, а значит компилятору придется проводить неявную инстанциацию. А мы как раз и добивались, чтобы этого не было. И правило "на любое явное объявление инстанциации обязательно нужно предоставить явное определение инстанциации" по-прежнему работает.
Просто интересно было показать, как такое небольшое изменение может развернуть ситуацию на 180. И кстати, если все-таки держать отдельно описание класса и его определение, но пометить метод inline, то будет тот же эффект, который я описал выше.
Pay attention to small details. Stay cool.
#template #compiler #cppcore
Возьмем пример из прошлого поста, объединим в хэдэре объявление шаблона с его определением и выкинем ship.cpp. И попробуем скомпилировать только main.cpp.
// ship.hpp
#pragma once
template<typename T>
struct Ship
{
int i = 0;
void TurnShip(T command) {i++;}
};
// main.cpp
#include "ship.hpp"
#include <string>
#include <iostream>
extern template class Ship<std::string>;
int main() {
Ship<std::string> ship;
ship.TurnShip(std::string{"Turn upside down"});
std::cout << ship.i << std::endl;
}
И неожиданно, все компилируется и выводится единичка. Почему так? Мы ведь почти ничего не поменяли даже просто нагло и беспардонно выкинули так нам необходимую единицу трансляции с явным инстанированием. Как это работает?
Дело в том, что любой метод, определенный внутри описания класса, неявно помечается inline. А на инлайн сущности не работает эффект подавления неявной специализации. Стандарт вот что говорит об этом:
Except for inline functions and class template specializations,
explicit instantiation declarations have the effect of suppressing
the implicit instantiation of the entity to which they refer.
Кажется, тут можно такую цепочку мыслей провести: компилятору запрещается делать неявную инстанциацию строкового корабля. Но он ее может и не делать, а просто встроить вызов метода этой инстанциации внутрь функции main и дело в шляпе! И ничего не нарушили и все работает.
Естественно, на это полагаться нельзя, потому что не любой метод может быть встроен, а значит компилятору придется проводить неявную инстанциацию. А мы как раз и добивались, чтобы этого не было. И правило "на любое явное объявление инстанциации обязательно нужно предоставить явное определение инстанциации" по-прежнему работает.
Просто интересно было показать, как такое небольшое изменение может развернуть ситуацию на 180. И кстати, если все-таки держать отдельно описание класса и его определение, но пометить метод inline, то будет тот же эффект, который я описал выше.
Pay attention to small details. Stay cool.
#template #compiler #cppcore