Создание экземпляра шаблона - это функция кода, а не функция каких-либо динамических условий выполнения.В качестве упрощенного примера:
template <typename T> void bar();
void foo(bool b) {
if (b) {
bar<int>();
} else {
bar<double>();
}
}
Здесь создаются экземпляры bar<int>
и bar<double>
, даже если foo
никогда не вызывается или даже если foo
вызывается только с true
.
Для шаблона переменной, в частности, применяется правило [temp.inst] / 6 :
Если специализация шаблона переменной не была явно создана или явно специализированаспециализация шаблона переменной неявно создается, когда на нее ссылаются в контексте, для которого требуется определение переменной, или если наличие определения влияет на семантику программы.
В вашей функции:
friend void fn()
{
(void)AnchorObjT<123>;
};
AnchorObjT<123>
упоминается в контексте, который требует определения (независимо от того, вызывается ли fn()
когда-либо или даже, в этом случае, даже возможно вызвать)следовательно, он создан.
Но AnchorObjT<123>
- глобальная переменная, поэтому ее создание означает, что у нас есть объект, созданный до main()
- к моменту ввода main()
конструктор AnchorObjT<123>
будет запущен, установив StaticInt
в 123
.Обратите внимание, что нам не нужно на самом деле запускать fn()
для вызова этого конструктора - здесь роль fn()
заключается просто в создании экземпляра шаблона переменной, его конструктор вызывается в другом месте.
Печать 123 правильна,ожидаемое поведение
Обратите внимание, что хотя для существования языка необходим глобальный объект AnchorObjT<123>
, компоновщик может по-прежнему оставаться объектом, поскольку на него нет ссылок.Предполагая, что ваша реальная программа делает больше с этим объектом, если вам нужно, чтобы он существовал, вам, возможно, придется сделать с ним больше, чтобы компоновщик не удалил его (например, gcc имеет атрибут used
).