Каков порядок инициализации статических данных-членов класса шаблона в файле? - PullRequest
7 голосов
/ 14 июля 2011

В данном файле, если у меня есть,

struct A { static int a; };
struct B { static int b; };
int A::a;
int B::b;

Тогда я всегда могу ожидать, что A::a инициализируется до B::b.Теперь для того же файла возьмем случай template,

template<typename T>
struct X { static T t; };
template<typename T>
T X<T>::t;

Предположим, что X создается с A и B, а его член static произвольно используется где-то в кодекак, X<A>::t и X<B>::t, тогда каким должен быть порядок инициализации template статического члена X<T>::t;?Это хорошо определено?

Ответы [ 4 ]

4 голосов
/ 14 июля 2011

Пока шаблоны имеют только одно определение (например, у вас есть только одна единица перевода), оно четко определено. Статические члены инициализируются в порядке, в котором специализации шаблона создаются в контекстах, которые требуют определения элемента статических данных . Из §14.7.1 / 1 [temp.inst] стандарта C ++ 03 (выделено мое):

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

§14.7.1 / 7 также гласит:

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

Однако все становится сложнее, когда у вас есть несколько единиц перевода, которые определяют шаблон. § 3.2 / 5 [basic.def.odr] гласит:

Может быть несколько определений типа класса (раздел 9), типа перечисления (7.2), встроенной функции с внешней связью (7.1.2), шаблона класса (раздел 14), шаблона нестатической функции (14.5). .5), статический член данных шаблона класса (14.5.1.3), функция-член шаблона класса (14.5.1.1) или специализация шаблона, для которого некоторые параметры шаблона не указаны (14.7, 14.5.4) в программе при условии, что каждое определение появляется в отдельной единице перевода, и при условии, что определения удовлетворяют следующим требованиям. Если такая сущность с именем D определена более чем в одной единице перевода, то

(список условий ...)

Если определения D удовлетворяют всем этим требованиям, то программа должна вести себя так, как если бы было одно определение D. Если определения D не удовлетворяют этим требованиям, то поведение не определено.

Обратите внимание, что стандарт не определяет , какое определение принимается за единственное определение, только то, что выбрано некоторое определение . Таким образом, если несколько модулей перевода создают шаблоны в разных порядках, нет никакой гарантии, какой будет порядок инициализации.

1 голос
/ 14 июля 2011

Из проекта стандарта C ++ 0x , раздел 3.6.2:

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

Поэтому, чтобы ответить на ваш вопрос, статические данные-члены явным образом созданных шаблонов не гарантируютсябыть инициализированным в любом конкретном порядке в C ++ 0x.

Я оставляю это другим, чтобы найти соответствующий язык (или его отсутствие) в более раннем стандарте (ах).

1 голос
/ 14 июля 2011

От 14.7.2 / 7:

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

Таким образом, мы можем заключить, что для экземпляров, для которых явно созданы экземпляры, их статические элементы создаются / создаются в том же порядке.

Однако для шаблонов, для которых неявно создаются экземпляры, мы переходим к 14.7.1 / 1:

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

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

1 голос
/ 14 июля 2011

Следующее - мое наблюдение (на основе gcc):

Все, что появляется первым, создается первым.

Если в заданной единице перевода (то есть предварительно обработано * 1007)* file), если компилятор (синтаксический анализатор) сначала видит использование X<A>::t, то сначала он создается, либо сначала он видит X<B>::t, а затем - сначала.Обратите внимание, что это перед компиляцией (не во время выполнения).

Например,

struct A { static int a; };
struct B { static int b; };

template<typename T> struct X { static T t; };
template<typename T> T X<T>::t;

void foo ()
{
  B *p = &(X<B>::t);
}

int main ()
{
  A *p = &(X<A>::t);
  foo();
}

Результат:

X<B>::t instantiated first
X<A>::t instantiated second

Причина:

X<B>::t появляется первым внутри foo()

...