Генерация статической таблицы работает с GCC, но не clang; прослушивается лязг?

Однажды я написал некоторый код, который генерировал статическую таблицу / массив во время компиляции для некоторого метапрограммирования шаблона (идея заключается в том, что строки в стиле C можно создавать во время компиляции (они просто char Массивы)). Идея и код основаны на ответе David Lin:

#include <iostream>

const int ARRAY_SIZE = 5;

template <int N, int I=N-1>
class Table : public Table<N, I-1>
{
public:
    static const int dummy;
};

template <int N>
class Table<N, 0>
{
public:
    static const int dummy;
    static int array[N];
};

template <int N, int I>
const int Table<N, I>::dummy = Table<N, 0>::array[I] = I*I + 0*Table<N, I-1>::dummy;

template <int N>
int Table<N, 0>::array[N];

template class Table<ARRAY_SIZE>;

int main(int, char**)
{
    const int *compilerFilledArray = Table<ARRAY_SIZE>::array;
    for (int i=0; i < ARRAY_SIZE; ++i)
        std::cout<<compilerFilledArray[i]<<std::endl;
}

Компиляция этого кода с GCC 4.9.2 работает:

$ g++-4.9 -Wall -pedantic b.cpp
$ ./a.out
0
1
4
9
16

Clang 3.5 жалуется, хотя:

$ clang++ -Wall -pedantic b.cpp
Undefined symbols for architecture x86_64:
  "Table<5, 0>::dummy", referenced from:
      ___cxx_global_var_init in b-b8a447.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

dummy а также array оба даны определения за пределами Table класс (где они объявлены). Насколько я могу судить, это должно удовлетворять требованиям компоновщика.

Это ошибка с Clang?

1 ответ

Решение

Каждая первичная и частичная специализации статических данных-членов должны быть определены отдельно.

template <int N, int I>
const int Table<N, I>::dummy = …;

Единственное, что здесь определено Table<N, I>::dummy - член статических данных основной специализации. [temp.class.spec.mfunc] / 1 1:

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

Это также подразумевает, что GCC здесь не прав. Это ошибка.
В любом случае, добавив

template <int N>
const int Table<N, 0>::dummy = 0;

Должен скомпилироваться нормально.


1) В частности, в том же разделе, что и цитата выше:

Список параметров шаблона члена частичной специализации шаблона класса должен соответствовать списку параметров шаблона частичной специализации шаблона класса.
Список аргументов шаблона члена частичной специализации шаблона класса должен соответствовать списку аргументов шаблона частичной специализации шаблона класса.

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

Другие вопросы по тегам