C++ 编译器错误?g++;允许可变大小的静态数组,除非函数已模板化
下面的代码演示了GCC4.6.2的一个行为,我对此无法解释。第一个函数声明vec_t类型的静态数组,其中vec_t是unsigned char的typedef别名。第二个函数相同,只是vect_t的类型是一个模板参数。第二个函数编译失败,诊断为“错误:'bitVec'的存储大小不是常量” 换句话说,如果用整型表达式初始化C++ 编译器错误?g++;允许可变大小的静态数组,除非函数已模板化,c++,templates,gcc,dynamic-arrays,C++,Templates,Gcc,Dynamic Arrays,下面的代码演示了GCC4.6.2的一个行为,我对此无法解释。第一个函数声明vec_t类型的静态数组,其中vec_t是unsigned char的typedef别名。第二个函数相同,只是vect_t的类型是一个模板参数。第二个函数编译失败,诊断为“错误:'bitVec'的存储大小不是常量” 换句话说,如果用整型表达式初始化nbits,则nbits在bitVec的定义中被视为常量。如果使用浮点表达式初始化nbits,编译器将不再将其视为bitVec维度表达式中的常量,编译将失败 我在C++中调用“编
nbits
,则nbits
在bitVec
的定义中被视为常量。如果使用浮点表达式初始化nbits
,编译器将不再将其视为bitVec
维度表达式中的常量,编译将失败
<>我在C++中调用“编译器错误”比在C中要舒服得多,但是我想不出任何其他原因,上述4种情况在语义上是不一样的。还有人愿意发表意见吗?答案肯定是,在生成错误的编译阶段,数组索引的存储大小不是恒定的——即,它位于模板扩展的上游。动态数组不是C++ 98/03的一部分,它们是GCC扩展(C,最初是C)。所以这个错误实际上是正确的,即使实现看起来很奇怪。大概GCC会为模板化数组找到一条符合标准的路径,在需要时支持它们,否则会抛出错误,但静态类型的数组会找到“C”路径,从而自动获取GCC扩展。在GCC 4.7.0上使用
-ansi
编译代码后,我能够重现此警告:
warning: ISO C++ forbids variable length array 'bitVec' [-Wvla]
此警告针对的是两个bitVec
,而不仅仅是模板函数中的一个。然后我意识到行nbits=1e7
正在将一个双精度
赋值给一个无符号整数
。我认为正因为如此,出于某种原因,nbits
不是一个常量表达式。代码为非模板版本编译的原因是gcc的可变长度数组扩展。另外,由于某些原因,您的gcc版本不允许在函数模板中使用可变长度数组。修复代码更改1e7代码>至10000000
编辑
我问有关规则的问题。答案是,在C++03中,代码无效,但在C++11中,代码没有问题。您能否发布导致编译器错误的确切代码?我似乎无法复制它。这正是上面的代码。编译器是GCC4.6.2,选项是“-O0-g3-c”。在旧的GCC4.3.4上,这段代码很有趣。我一字不差地复制了您的代码,并在4.6.2中重现了错误。也许这是一个相对较新的“功能”:)感谢您的检查。很抱歉,我以前没有意识到,但是您想用nbits=1e7代码>?如果您试图将一个十六进制值赋给一个无符号int,那么这将不起作用(我认为这也是问题所在)。代码实际上没有变量数组,因此错误是错误的。数组的大小在编译时是已知的,应该由一致的编译器来处理。这不仅仅是运行时可变性的问题。我相信(但我懒得去检查),C++03特别在数组大小的初始值设定项中不允许使用模板参数(正是因为在正确的时间进行扩展时存在鸡和蛋的问题)。毫无疑问,会有更了解规范的人来纠正我。很有趣。这(混乱)是有效的:template void a(){typedef T vec_T;static vec_T bitVec[sizeof(vec_T)*8]}
它并没有失去它的const
属性,而是(隐含的)constepr
属性。@moingduck:这是真的(已更正)。然而,我仍然想知道为什么会是这样。1e7
和0x1e7
是非常不同的数字<代码>10000000
将是一个更好的替代品。如上所述,1e7(10000000)是预期的。这似乎是问题的症结所在。IANAL,但我的理解是,inti=123.4
将浮点常量转换为int,并使用结果初始化i
。但是,将“nbits
”初始值设定项从1e7
更改为10000000
,甚至(std::size_t)1e7
可以消除错误。@JohnA:请参阅我答案中的链接。在C++03中,inti=123.4
是无效的,但在C++11中,规则发生了变化,这是正常的。
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
warning: ISO C++ forbids variable length array 'bitVec' [-Wvla]