使用(输出)常量表达式定义数组

Defining arrays with(out) constant expressions

我正在慢慢将自己提升到 c++11。我在查看 constexpr 时无意中发现了这个 wikipedia article,这让我找到了 "something completely different"。它给出的基本示例是:

int get_five() {return 5;}
int some_value[get_five() + 7]; // Create an array of 12 integers. Ill-formed C++

它指出 "This was not legal in C++03, because get_five() + 7 is not a constant expression." 并说在 get_five() 声明中添加 constexpr 可以解决问题。

我的问题是"What problem?"。我编译了该代码,既没有错误也没有警告。我玩弄它使它非常不稳定:

#include <iostream>

int size(int x) { return x; }

int main()
{
  int v[size(5) + 5];
  std::cout << sizeof(v) + 2 << std::endl;
}

编译时没有抱怨:

g++ -Wall -std=c++03

执行时我得到(正确的)答案 42。

我承认我一般用的是stl容器,而不是数组。但我认为(维基百科显然也是如此)上述代码的编译会惨败。为什么会成功?

一些编译器有扩展,实现了 VLA(可变长度数组)。

使用 -pedantic 编译,您会看到不同之处。

C 中允许可变长度数组(即,其大小由非常量表达式确定的数组),并且一些 C++ 编译器允许它们作为语言的扩展。 GCC 就是这样一种编译器。

如果您使用 -pedantic-Wvla 进行编译,或者使用 -pedantic-errors 进行编译,您将收到警告。如果您想避免非标准编译器扩展,请使用这些标志。

如前所述,一些 C++ 编译器支持名为可变长度数组的 C 功能,其大小可以在 运行 时指定。

但是,VLA 不能声明为静态存储持续时间。您展示的节目

#include <iostream>

int size(int x) { return x; }

int main() 
{
    int v[size(5) + 5];
    std::cout << sizeof(v) + 2 << std::endl;

    return 0;
}

可以编译。但是,如果您将数组放在任何函数之外,那么代码将不会被编译。考虑以下与您的原始程序类似但稍作更改的程序。

#include <iostream>

int size(int x) { return x; }

int v[size(5) + 5];

int main() 
{
    std::cout << sizeof(v) + 2 << std::endl;

    return 0;
}

在这种情况下编译器会报错。但是,如果您为函数大小指定 constexpr,则上述程序将成功编译

#include <iostream>

constexpr int size(int x) { return x; }

int v[size(5) + 5];

int main() 
{
    std::cout << sizeof(v) + 2 << std::endl;

    return 0;
}

C++ 标准要求数组的大小是常量表达式。

8.3.4 数组 [dcl.array]

1 在声明 T D 中,其中 D 的形式为

D1 [ constant-expressionopt] attribute-specifier-seqopt

而声明T D1中的标识符类型为“derived-declarator-type-list T”,则D的标识符类型为数组类型;

请注意,并非所有 C++ 编译器(甚至 C 编译器;对于 C 编译器,编译器是否支持 VLA 由实现定义)都具有 VLA 这样的语言扩展。因此,如果您希望您的程序与 C++ 兼容,那么您不应依赖编译器的特定语言扩展。