I wrote some code once upon a time that generated a static table/array at compile time for some template metaprogramming (the idea is that C-style strings can be built at compile time (they're just char
arrays)). The idea and the code is based off David Lin's answer:
#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;
}
Compiling this code with GCC 4.9.2 works:
$ g++-4.9 -Wall -pedantic b.cpp
$ ./a.out
0
1
4
9
16
Clang 3.5 complains, though:
$ 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
and array
are both given definitions outside of the Table
class (where they're declared). As far as I can tell, this should satisfy the linker requirements.
Is this a bug with clang?
Every primary and partial specializations static data members must be defined separately.
template <int N, int I>
const int Table<N, I>::dummy = …;
The only thing defined here is Table<N, I>::dummy
- the primary specializations static data member. [temp.class.spec.mfunc]/11:
Class template partial specialization members that are used in a way that requires a definition shall be defined; the definitions of members of the primary template are never used as definitions for members of a class template partial specialization.
This also implies that GCC is wrong here. That's a bug.
Eitherway, adding
template <int N>
const int Table<N, 0>::dummy = 0;
Should compile fine.
The template parameter list of a member of a class template partial specialization shall match the template parameter list of the class template partial specialization.
The template argument list of a member of a class template partial specialization shall match the template argument list of the class template partial specialization.
That means that the argument lists used for defining the partial specialization and its member must be the same. Otherwise that member is never defined.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With