2015-04-27 3 views
0

рассмотрим следующий код:шаблона класса, в C++

//header.h 
template<class T> 
class A 
{ 
    static int x; 
}; 

template<class T> 
int A<T>::x = 0; 

//source1.cpp 
#include "header.h" 
void f(){} // dummy function 


//main.cpp 
#include "header.h" 
int main(){} 

В этом случае код компилирует совершенно без ошибок, но если удалить шаблон спецификатор из класса

class A 
{ 
    static int x; 
}; 

int A::x = 0; 
  1. В этот компилятор случая ошибочен с множественным определением x. Может ли кто-нибудь объяснить это поведение?
  2. И когда статическая переменная класса шаблона инициализируется/создается?
+0

1) Члены шаблона класса создаются только при необходимости. 2) Это сложный вопрос. –

+0

Возможный дубликат [Статическая переменная шаблона] (http://stackoverflow.com/questions/1553854/template-static-variable) – Quentin

+0

Короче говоря, ** никогда ** не создавайте статику в заголовочных файлах, это почти каждый раз будет создавать проблемы , Каждый раз, когда заголовочный файл включается, статика создается. – bkausbk

ответ

2

Компилятор самостоятельно удалит повторяющиеся экземпляры шаблонов. Если вы превратите свой шаблонный класс в обычный, то его обязанность состоит в том, чтобы убедиться, что существует только одно определение статической переменной (иначе появится ошибка компоновщика). Также помните, что статические члены данных не разделяются между установками шаблонов для разных типов. С помощью C++ 11 вы можете самостоятельно управлять установками с использованием шаблонов extern: using extern template (C++11).

Что касается точки instatiation для статических членов:

14.6.4.1 Точки конкретизации [temp.point] 1 Для шаблона функции специализации, функции члена специализации шаблона, или специализаций при а Функция-член или статический элемент данных шаблона класса, если специализация неявно создана , потому что на нее ссылаются из другой специализированной специализации и контекст, с которой она ссылается зависит от параметра шаблона, точки создания экземпляра специализация n - это точка экземпляр прилагаемой специализации. В противном случае точка инстанцирования для такой специализации сразу следует за объявлением или определением области пространства имен, которое относится к специализации.

Таким образом, точка instatiation должна быть то есть. сразу после main(), если вы впервые используете свой тип в main().

+0

Итак, когда стандарт C++ настаивает на том, что все статические данные должны быть инициализированы до того, как main не побеспокоит этот случай, я прав? –

+0

Конструкторы статических членов класса шаблонов, несомненно, будут выполнены до выполнения основных функций. POI (Point of Instation) создается, когда конструкция кода ссылается на специализацию шаблона таким образом, что требуется его определение. – marcinj

0

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

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

0
  1. Необходимо создать/инициализировать статические элементы в файлах cpp, не входящих в заголовки. Статические члены - это свойство класса, не являющегося собственностью объектов, поэтому, если вы включаете заголовочный файл в больше файлов cpp, похоже, что вы его инициализируете больше раз.

  2. Ответ на этот вопрос более сложный. Шаблон не один класс. Он создается по требованию. Это означает, что любое другое использование шаблона - это один отдельный «экземпляр шаблона». Например, если вы используете A<int> и A<float>, то у вас будет 2 разных класса, поэтому вам нужно будет инициализировать A<int>::x и A<float>::x.

Для получения дополнительной информации см этот ответ: https://stackoverflow.com/a/607335/1280316

+0

Это не только хорошая практика, это требование или ODR. Если ни один из ваших заголовков не будет включен несколькими TU. – Quentin

0

Класс (будь то шаблон или нет) может (и должен) быть объявлены в любом модуле компиляции, что referes к нему.

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

Но когда вы объявляете шаблон, ничего не создается, пока вы его не создадите. Поскольку вы никогда не создаете экземпляр шаблона, статическое поле никогда не определяется и вы не получаете ошибки.

Если у вас есть два различных инстанциацию в source1.cpp (скажем A<B>) и main.cpp (скажем A<C>) все еще будет хорошо: вы получите A<B>::x в Source1 и A<C>::x в основных => двух различных переменных, так как A<B> и A<C> разные классы ,

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

Смежные вопросы