编译错误?g ++允许可变大小的静态数组,除非函数是模板化的

Joh*_*uld 6 c++ gcc templates dynamic-arrays

下面的代码演示了我无法解释的gcc 4.6.2的行为.第一个函数声明一个类型为vec_t的静态数组,其中vec_t是unsigned char的typedef'd别名.除了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>();
}
Run Code Online (Sandbox Code Playgroud)

在我看来,使用参数<unsigned char>实例化模板应该使编译器生成与第一个函数相同的代码.任何人都可以提供任何洞察力,为什么这似乎不是这样的?

[附录:第二个函数使用"-std = c ++ 0x"或"-std = gnu ++ 0x"进行编译,但我仍然想了解在早期语言定义下如何/是否错误.]

ETA:
如果更改了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
Run Code Online (Sandbox Code Playgroud)

换句话说,似乎if nbits用一个整数类型的表达式初始化,然后nbits在定义中被视为常量bitVec.如果nbits使用浮点表达式初始化,则编译器不再将其视为维度的表达式中的常量bitVec,并且编译失败.

我在C++中调用"编译器错误"比在C中调用错误要差得多,但我想不出上述4个案例在语义上不相同的任何其他原因.还有其他人关心吗?

Jes*_*ood 6

在使用-ansigcc 4.7.0 编译代码后,我能够重现此警告:

warning: ISO C++ forbids variable length array 'bitVec' [-Wvla]
Run Code Online (Sandbox Code Playgroud)

两个 警告都出现bitVec,而不仅仅是模板功能中的警告.然后我意识到这条线nbits = 1e7;正在分配double给一个unsigned int.我认为正因为如此,由于某种原因导致nbits不是一个恒定的表达.您的代码为非模板化版本编译的原因是因为gcc的可变长度数组扩展.此外,由于某种原因,您的gcc版本不允许在函数模板中使用可变长度数组.修改代码更改1e7;10000000.

编辑

我问了另一个关于这条规则的问题.答案是在C++ 03中代码无效,但在C++ 11中它是可以的.