下面的代码演示了我无法解释的 gcc 4.6.2 行为。第一个函数声明一个 vec_t 类型的静态数组,其中 vec_t 是 unsigned char 的 typedef 别名。第二个函数是相同的,除了 vect_t 的类型是一个模板参数。第二个函数无法编译并出现诊断“错误:‘bitVec’ 的存储大小不是常量”。
#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>();
}
在我看来,使用参数
[附录:第二个函数将用“-std=c++0x”或“-std=gnu++0x”编译,但我仍然想了解如何/如果在早期的语言定义下是错误的。]
预计到达时间:
如果更改了 nbits 的初始化程序,第二个函数将编译:
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
换句话说,似乎如果nbits
是用整数类型的表达式初始化的,那么nbits
在的定义中被当作一个常量比特 vector
。如果 nbits
改为使用浮点表达式进行初始化,则编译器不再将其视为 bitVec
维度表达式中的常量,并且编译失败。
与在 C 中相比,我在 C++ 中称呼“编译器错误”要不舒服得多,但我想不出上述 4 种情况在语义上不相同的任何其他原因。还有其他人愿意发表意见吗?
最佳答案
在 gcc 4.7.0 上使用 -ansi
编译您的代码后,我能够重现此警告:
warning: ISO C++ forbids variable length array 'bitVec' [-Wvla]
此警告出现在 both bitVec
中,而不仅仅是模板函数中的那个。然后我意识到 nbits = 1e7;
行正在将 double
分配给 unsigned int
。我认为正因为如此,由于某种原因导致 nbits
不是常量表达式。您的代码为非模板版本编译的原因是因为 gcc 的可变长度数组扩展。此外,出于某种原因,您的 gcc 版本不允许在函数模板中使用可变长度数组。要修复您的代码,请将 1e7;
更改为 10000000
。
编辑
我问了another question关于规则。答案是在C++03中代码无效,但在C++11中没问题。
关于c++ - 编译器错误? g++ 允许可变大小的静态数组,除非函数是模板化的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10923615/