Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static table generation works with GCC but not clang; is clang bugged?

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?

like image 604
Cornstalks Avatar asked Dec 05 '14 17:12

Cornstalks


1 Answers

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.


1) In particular, in the same section as the quote above:

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.

like image 141
Columbo Avatar answered Oct 27 '22 10:10

Columbo