Consider the following code:
#include
#include
using namespace std;
// base template
template
struct what_type
{
void operator()()
{
cout << "T" << endl;
}
};
// specialization 1
template
struct what_type
{
void operator()()
{
cout << "T[" << N << "]" << endl;
}
};
// specialization 2
template <>
struct what_type
{
void operator()()
{
cout << "int[0]" << endl;
}
};
int main(void)
{
int x[] = {};
what_type>()();
return 0;
}
I compile this with GCC (g++ (Ubuntu 4.9.1-16ubuntu6) 4.9.1) and I get:
bdeane@epsilon:~/dev/scratch$ g++ -std=c++1y main.cpp
bdeane@epsilon:~/dev/scratch$ ./a.out
T
When I use clang (Ubuntu clang version 3.5.0-4ubuntu2 (tags/RELEASE_350/final) (based on LLVM 3.5.0)) I get:
bdeane@epsilon:~/dev/scratch$ clang++ -std=c++1y main.cpp
bdeane@epsilon:~/dev/scratch$ ./a.out
int[0]
It seems GCC is wrong here: I would expect specialization 2 to be selected. Now, if I remove specialization 2, clang gives the same output as GCC (i.e. T
).
If I put an assert in the base template member function, both clang and gcc think that T = int[0]
and give almost identical messages:
a.out: main.cpp:53: void what_type<int [0]>::operator()() [T = int [0]]: Assertion `false' failed.
So why isn’t specialization 1 selected? (And it makes no difference either if I have a specialization for T[]
as well as/instead of T[N]
.)
Edit:
Zero-sized arrays are illegal in C++, although GCC and Clang both compile them by default, presumably for historical reasons. If I turn on pedantic
, both give me a warning.
From n4296 8.5.1 section 4:
An empty initializer list {} shall not be used as the initializer-clause for an array of unknown bound. (note 105)
105) The syntax provides for empty initializer-lists, but nonetheless C++ does not have zero length arrays.
So if GCC/Clang are going to allow zero-length arrays, I think they should be consistent about it and do specialization “correctly”. A friend reports that Clang/LLVM 3.3 does what GCC does here and uses the base template. Clang/LLVM 3.5 uses specialization 2, which is “more” correct. I have yet to try with Clang/LLVM 3.6+.
Edit 2:
Clang 3.7 produces the same output as clang 3.5.