статическая инициализация члена для специализированного шаблонного класса - PullRequest
17 голосов
/ 26 февраля 2010
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'

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

Ответы [ 3 ]

35 голосов
/ 26 февраля 2010

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

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

2 голосов
/ 26 февраля 2010

Вам необходимо присвоить ему значение.

template<> int B<A, 1>::a[1] = {0};
1 голос
/ 26 февраля 2010

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

template<> int B<A, 1>::a[] = { 0 };

Edit:

Кстати: я бы предпочел использовать 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...