我正在慢慢将自己升级到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容器,而不是数组。但我认为(显然维基百科也是这样)上述代码的编译会失败。它为什么成功?
答案 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
汇编,您将看到差异。