#include <iostream>
template <typename T>
class Temp {
public:
static Temp temp;
Temp() { std::cout << "hi!"; }
};
// Definition.
template <typename T>
Temp<T> Temp<T>::temp;
Я создал простой класс шаблона. Я думал, что создания экземпляра объекта Temp
достаточно для создания статического temp
в Temp
.
int main() {
Temp<int> t;
}
Но это ответило только одним «привет!».
Принимая во внимание, что если я явно ссылаюсь на temp
,
int main() {
Temp<int> t;
Temp<int>::temp;
}
он напечатал "привет!" два раза, и я мог подтвердить, что статический объект был создан во время его обычной инициализации (перед вызовом main). Каковы критерии компилятора для исключения построения статического объекта? Кроме того, как я могу обеспечить его соблюдение, кроме ссылки на него?
У вас нет под рукой стандарта, но посмотрите ссылку в конце вопроса Инициализация статического члена C++ (шаблон весело внутри). Исправление к моему первому (теперь удаленному) комментарию: статические элементы шаблона не создаются, если на них не ссылаются, или специализация явно объявлена.
Для работы шаблонов довольно важно, чтобы неиспользуемый код не создавался, например. такие вещи, как std::vector
с некопируемым типом, работают до тех пор, пока вы не вызываете определенные методы
Вы можете явно создать экземпляр класса, чтобы повысить вероятность включения члена static
без ссылки на него:
template class Temp<int>;
Обратите внимание, однако, что в зависимости от параметров компилятора/компоновщика код без ссылок не обязательно включается в окончательный двоичный файл. В частности, любая попытка зарегистрировать что-либо с помощью объекта обречена на провал! Например, для больших сборок довольно часто используются специальные разделы для функций и объектов, а компоновщики ELF будут включать только разделы, на которые есть ссылки.
Шаблон обычно создается только тогда, когда это необходимо. Обычно это означает, что на них есть ссылки («ODR-используется» в стандарте). Вы можете принудительно создать экземпляр с помощью явного создания, как показано выше. Однако даже после создания экземпляра компилятором компоновщик может удалить неиспользуемый код. Конечно, что-то, регистрирующее объект в некотором реестре, не является «неиспользуемым кодом» с вашей точки зрения, но это неиспользуемый код с точки зрения компоновщика. Компоновщик обычно работает с разделами, которые, в свою очередь, обычно основаны на файлах, но есть варианты, чтобы указать разделы или заставить компилятор генерировать более мелкие разделы, чтобы уменьшить размер исполняемого файла.
@dxiv есть ли какая-нибудь ссылка, которую я могу найти об этом?