The code below demonstrates a behavior of gcc 4.6.2 that I can't account for. The first function declares a static array of type vec_t, where vec_t is a typedef'd alias for unsigned char. The second function is identical, except that the type of vect_t is a template parameter. The second function fails to compile with diagnostic "error: storage size of ‘bitVec’ isn’t constant".
#include <limits>
void bitvec_func()
{
const std::size_t nbits = 1e7;
typedef unsigned char vec_t;
const std::size_t WLEN = std::numeric_limits<vec_t>::digits;
const std::size_t VSIZ = nbits/WLEN+1;
static vec_t bitVec[nbits/VSIZ]; // Compiles fine
}
template <typename T>
void bitvec_func()
{
const std::size_t nbits = 1e7;
typedef T vec_t;
const std::size_t WLEN = std::numeric_limits<vec_t>::digits;
const std::size_t VSIZ = nbits/WLEN+1;
static vec_t bitVec[nbits/VSIZ]; // "error: storage size of ‘bitVec’ isn’t constant"
}
void flarf()
{
bitvec_func();
bitvec_func<unsigned char>();
}
It seems to me that instantiating the template with argument <unsigned char> should cause the compiler to generate the same code as the first function. Can anyone offer any insight into why this does not seem to be the case?
[Addendum: the second function will compile with "-std=c++0x" or "-std=gnu++0x", but I'd still like to understand how/if it's wrong under the earlier language definitions.]
ETA:
The second function will compile if the initializer for nbits is changed:
const std::size_t nbits = 1e7; // Error
const std::size_t nbits = (std::size_t)1e7; // Okay
const std::size_t nbits = 10000000.0; // Error
const std::size_t nbits = 10000000; // Okay
In other words, it seems that if nbits
is initialized with an expression of an integral type, then nbits
is treated as a constant in the definition of bitVec
. If nbits
is instead initialized with a floating-point expression, the compiler no longer sees it as constant in the expression for the dimension of bitVec
, and the compilation fails.
I'm a lot less comfortable calling "compiler bug" in C++ than I would be in C, but I can't think of any other reason that the above 4 cases would not be semantically identical. Anyone else care to opine?
After compiling your code with -ansi
on gcc 4.7.0, I was able to reproduce this warning:
warning: ISO C++ forbids variable length array 'bitVec' [-Wvla]
This warning appeared for both bitVec
, not just the one in the template function. I then realized that the line nbits = 1e7;
is assigning a double
to an unsigned int
. I think because of this, for some reason causes nbits
to not be a constant expression. The reason your code is compiling for the non-templated version is because of the variable length array extension for gcc. Also, your version of gcc for some reason doesn't allow variable length arrays in function templates. To fix your code change 1e7;
to 10000000
.
EDIT
I asked another question concerning the rule. The answer is in C++03 the code is invalid, but in C++11 it is okay.
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