Я имею в виду, что именно создается, когда вы создаете экземпляр переменной шаблона, отличной от constexpr
?
Рассмотрим базовый шаблон переменной, который вычисляет факториал:
template<int N>
int fat = N*(fat<N-1>);
template<>
int fat<0> = 1;
int main() {
return fat<5>;
}
Моя интуиция подсказывает, что это сгенерирует что-то вроде этого:
int fat0 = 1;
int fat1 = 1*fat0;
int fat2 = 2*fat1;
int fat3 = 3*fat2;
int fat4 = 4*fat3;
int fat5 = 5*fat4;
int main() {
return fat5;
}
Я попытался взглянуть на это на C ++ Insights, но сгенерированный код выглядит так:
template<int N>
const int fat = N*(fat<N-1>);
template<>
const int fat<0> = 1;
int main()
{
return fat<5>;
}
... что совсем не помогает.
Моя следующая попытка заключалась в том, чтобы взглянуть на (оптимизированную) сгенерированную сборку с помощью godbolt.org и посмотреть, есть ли какие-либо разница:
К моему удивлению, есть! В шаблонной версии примерно вдвое больше строк сборки, чем в рукописной. Кажется, что GCC генерирует дополнительную «охранную переменную» для каждого экземпляра. Clang также делает то же самое.
Теперь, учитывая принцип нулевых накладных расходов, эти переменные должны делать что-то важное. Конкретно то, что я упустил при написании своей "развернутой" версии. Что это за "что-то", что мне не хватает?
P.S .: Чтобы еще больше повредить моему мозгу, MSVC идет обратным путем, и сгенерированная сборка для шаблонной версии на самом деле в 3 раза меньше, чем версия без шаблонов. Однако я не могу понять смысла созданной сборки, поэтому я исключил ее из основного вопроса.