Статическая переменная-член инициализируется в шаблонном классе, если статический menber не используется?

Является ли статическая переменная-член инициализированной в классе шаблона, если статический член не используется? Я использую его для регистрации типа.

template<class T>
class A
{
static bool d;
};

template<class T> bool A<T>::d = [](){regist<A<T>>(); return true;}();

int main()
{
A<int> a;
return 0;
}

Я нахожу способ проверить это. Он печатает 1, отличное от 2. Regist () не вызывается и статический член не инициализируется. Я тестирую компилятор VC110. И я тоже проверяю это онлайн

#include <iostream>
using namespace std;

int i = 1;

template<class T>
void regist()
{
++i;
}

template<class T>
class A
{
static bool d;
};

template<class T> bool A<T>::d = [](){regist<A<T>>(); return true;}();

int main()
{
A<int> a;
cout << i << endl;
return 0;
}

3

Решение

Соответствующий раздел Проект стандарта C ++ приходит под 14 Шаблоны который 14.7.1 Неявная реализация параграф 2 который говорит (акцент мой):

Если элемент шаблона класса или шаблон элемента не был явно создан или явно специализирован, специализация члена создается неявно, когда на специализацию ссылаются в контексте, который требует определения элемента; особенно, инициализация (и любые связанные побочные эффекты) элемента статических данных не происходит, если только сам элемент статических данных не используется таким образом, который требует определения элемента статических данных.

Мы также можем увидеть абзац 8 который говорит:

Неявное создание экземпляра шаблона класса не приводит к неявному созданию экземпляров статических данных-членов этого класса.

Однако, если вы добавите явная реализация ко второму случаю вы увидите следующее 2 как результаты:

template<> bool A<int>::d = [](){regist<A<int>>(); return true;}();
2

Другие решения

Да, это инициализированный запуск этого примера программы, но только потому, что он вынужден существовать.

template <class T>
struct A
{
static int b;
};
template <class T> int A<T>::b = 10;
#include <iostream>
using namespace std;
int main() {
cout << A<int>::b << endl;
return 0;
}

Я считаю, что эта цитата из стандарта может прояснить любые сомнения

[Примечание: После определения статического члена данных он существует, даже если не созданы объекты его класса. [Пример: в приведенном выше примере run_chain и running существуют, даже если программа не создает объекты класса процесса. — конец примера] — конец заметки]

Вот соответствующая часть стандарта, которая подтверждает ваши подозрения.

Если специализация шаблона класса не была явно создана (14.7.2) или явно специализирована (14.7.3), специализация шаблона класса создается неявно, когда на специализацию ссылаются в контексте, который требует полностью определенного типа объекта или когда полнота Тип класса влияет на семантику программы. Неявная реализация специализации шаблона класса вызывает неявную реализацию объявлений, но не определений или аргументов по умолчанию, функций членов класса, классов-членов, члены статических данных и шаблоны участников; и это вызывает неявную реализацию определений членских анонимных союзов. Если элемент шаблона класса или шаблон элемента не был явно создан или явно специализирован, специализация члена неявно создается, когда на специализацию ссылаются в контексте, который требует определения элемента; особенно, инициализация (и любые связанные побочные эффекты) элемента статических данных не происходит, если только сам элемент статических данных не используется таким образом, который требует определения элемента статических данных.

Две части, которые я выделил жирным шрифтом, я думаю, прояснит вашу проблему. Ясно, что причина такого поведения в том, что если не указана явная специализация, компилятор не может решить, сколько раз код должен быть выполнен (бесконечно много возможных типов)

2

По вопросам рекламы [email protected]