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

时间:2015-01-06 14:24:55

标签: c++ c++11

我正在慢慢将自己升级到c ++ 11。我看着constexpr并偶然发现了wikipedia article这导致我“完全不同的东西”。它给出的基本例子是:

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

它声明“这在C ++ 03中不合法,因为get_five()+ 7不是常量表达式。”并且说constexpr声明中添加get_five()可以解决问题。

我的问题是“什么问题?”。我编译的代码既没有错误也没有警告。我玩它使它非常不稳定:

#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容器,而不是数组。但我认为(显然维基百科也是这样)上述代码的编译会失败。它为什么成功?

3 个答案:

答案 0 :(得分:6)

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

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

答案 1 :(得分:2)

正如已经说过的,一些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 ++,那么您不应该依赖编译器的特定语言扩展。

答案 2 :(得分:1)

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

-pedantic汇编,您将看到差异。