class A
{
};
template <typename A, int S>
class B
{
public:
static int a[S];
B()
{
a[0] = 0;
}
};
template<> int B<A, 1>::a[1];
int main()
{
B<A, 1> t;
t;
}
Это компилирует под GCC 4.1, но не связывается:
static.cpp:(.text._ZN1BI1ALi1EEC1Ev[B<A, 1>::B()]+0x5): undefined reference to `B<A, 1>::a'
Я предпочел бы сохранять инициализацию специализированной, если это возможно, так как массив содержит некоторые данные, характерные для типа.
Он не ссылается, потому что вы не определяете значение для своего статического члена.
template<> int B<A, 1>::a[] = { 0 };
Изменить:
Кстати: я всегда предпочел бы использовать boost :: array вместо собственных C-типов:
class A { };
template <typename A, std::size_t S>
class B
{
public:
static boost::array<int, S> a;
B() { a[0] = 0; }
};
template<> boost::array<int, 1> B<A, 1>::a = { };
int main()
{
B<A, 1> t;
cout << t.a[0] << endl;
}
Вам нужно фактически присвоить ему значение.
template<> int B<A, 1>::a[1] = {0};
Для специализаций статических членов, если вы не инициализируете член, он используется как объявление специализации , в котором просто говорится: «О, не создавайте экземпляр члена из первичного шаблона, потому что там это специальное определение где-то еще ". Следует отметить, что определение должно появиться в файле .cpp (в противном случае вы получите противоположное: несколько определений), а объявление без инициализатора все равно следует поместить в файл заголовка.
Теперь правильный синтаксис действительно следующий, и он должен не отображаться в файле заголовка, а в файле .cpp
template<> int B<A, 1>::a[1] = { };
Следующее должно появиться в заголовочный файл:
template<> int B<A, 1>::a[1];
Он будет служить объявлением специализации .
Из этого следует, что вы не можете специализировать член, который имеет только конструктор по умолчанию и не может быть скопирован, потому что вам понадобится этот синтаксис:
// needs a copy constructor!
template<> Type Class<Arguments>::member = Type();
C ++ 0x исправляет это:
// doesn't anymore need a copy constructor
template<> Type Class<Arguments>::member{};
Для стандартного языка люди среди нас, вот цитаты:
14.7.3 / 6
:
Если шаблон, шаблон элемента или член шаблона класса явно специализированы, то эта специализация должна быть объявлена перед первой использование этой специализации, которая вызовет неявное создание экземпляра в каждой единице перевода, в которой такое использование происходит; Диагностика не требуется.
14.7.3 / 15
:
Явная специализация статического элемента данных шаблона - это определение, если объявление включает инициализатор; в противном случае это декларация.[Примечание: не существует синтаксиса для определения статического элемента данных шаблона, который требует инициализации по умолчанию.
template <> X Q
:: x; Это объявление независимо от того, может ли X быть инициализирован по умолчанию (8.5). ]
3.2 / 3
:
Каждая программа должна содержать ровно одно определение каждой не встроенной функции или объекта, которые используются в этой программе; диагностика не требуется.
3.2 / 5
:
Может быть несколько определений типа класса (пункт 9), типа перечисления (7.2), встроенной функции с внешней связью (7.1.2), шаблона класса (пункт 14), шаблон нестатической функции (14.5.5), член статических данных шаблона класса (14.5.1.3), функция-член шаблона класса (14.5.1.1) или специализация шаблона, для которой не указаны некоторые параметры шаблона. (14.7, 14.5.4) в программе [...]
Ограничение этого на «для которых не указаны некоторые параметры шаблона» означает, что нам разрешено делать следующее, помещая его в заголовок (таким образом, возможно, имея несколько определений этой специализации):
template<> template<typename T>
Type OuterClass<int>::InnerClass<T>::StaticMember = 0;
В вашем случае вы указали все параметры, что делает его не охваченным одним правилом определения для разрешения нескольких определений.