Считается ли динамическое создание шаблона класса явным или неявным?
Если у меня есть шаблон класса, и я использую умный указатель на динамически размещенный экземпляр специализированного экземпляра, это заставляет компилятор определять весь шаблон класса или он также будет ждать вызова функции-члена из указателя до того, как он будет создан?
template <class T>
class Test {
public:
void nothing();
void operation();
static const int value;
};
template <class T>
const int Test<T>::value = 100;
template <class T>
void Test<T>::nothing() {
/* invalid code */
int n = 2.5f;
}
template <class T>
void Test<T>::operation() {
double x = 2.5 * value;
}
int main() {
std::unique_ptr<Test<int>> ptr = new Test<int>(); // mark1
ptr->operation(); // mark2
return 0;
}
Весь шаблон класса инстанцируется в mark1?
Если нет, значит ли это, что этот код будет правильно скомпилирован, а функция-член Test::nothing() не будет создана?
3 ответа
Так что, как оказалось, для компилятора, который я использую (MS Visual C++), мое предположение было правильным, что для кода, представленного в вопросе, создание экземпляра члена шаблона класса не будет происходить //mark1
а скорее в //mark2
а также Test<int>.nothing()
не будет создан компилятором.
Тем не менее, похоже, я не учел критическую часть проблемы, с которой столкнулся. Мой реальный класс был частью виртуальной иерархии, и согласно справочной библиотеке MSDN все виртуальные члены создаются при создании объекта. Так в приведенном выше примере, если обе функции-члены, т.е. operation()
а также nothing()
, виртуальны тогда на //mark2
компилятор попытается сгенерировать код для обеих функций и проверки nothing()
потерпит неудачу
Весь шаблон класса инстанцируется в mark1?
Да. Шаблон класса создается неявно - только шаблон класса, а не все его члены.
Если нет, значит ли это, что этот код будет правильно скомпилирован, а функция-член Test::nothing() не будет создана?
Это не значит, скорее, если nothing()
не используется, это не мгновенно.
Полный ответ на этот вопрос, вероятно, сильно зависит от того, какой компилятор вы используете.
В //mark1
компилятор заметит, что по крайней мере части Test<int>
класс надо создавать. Делать это правильно или нет, на более позднем этапе, зависит от дизайнера компилятора.
В //mark2
, Test<int>.operation()
Очевидно, что он необходим, либо помечен для последующего создания, либо создан на месте, опять же в зависимости от того, что решили разработчики компилятора
поскольку Test<int>.nothing()
на него никогда не ссылаются, компилятор может свободно создавать его или нет. Некоторые старые компиляторы слепо создают экземпляр всего класса, но я подозреваю, что большинство современных компиляторов будут только создавать экземпляры того, что они могут оказаться необходимыми (или, по крайней мере, то, что они не могут доказать, не является необходимым). Опять же, однако, где это происходит внутри компилятора, зависит от того, как разработчики компилятора создали компилятор.