статическая членская инициализация для специализированного шаблонного класса

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'

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

17
задан kaspy 26 February 2010 в 15:11
поделиться

3 ответа

Он не ссылается, потому что вы не определяете значение для своего статического члена.

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;
}
1
ответ дан 30 November 2019 в 11:37
поделиться

Вам нужно фактически присвоить ему значение.

template<> int B<A, 1>::a[1] = {0};
2
ответ дан 30 November 2019 в 11:37
поделиться

Для специализаций статических членов, если вы не инициализируете член, он используется как объявление специализации , в котором просто говорится: «О, не создавайте экземпляр члена из первичного шаблона, потому что там это специальное определение где-то еще ". Следует отметить, что определение должно появиться в файле .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;

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

35
ответ дан 30 November 2019 в 11:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: