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

1

5

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?

Nightwalker answered 5/12, 2014 at 17:0 Comment(0)
P
6

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.

Playoff answered 5/12, 2014 at 17:9 Comment(3)
Ah, that makes sense! It's a shame I can only vote once. Also, I'm looking forward to the standard quotes when you get them.Nightwalker
@Nightwalker They're there :)Playoff
Can you add a link to the gcc bug report please?Mohammed

© 2022 - 2024 — McMap. All rights reserved.