使用(输出)常量表达式定义数组
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++ 兼容,那么您不应依赖编译器的特定语言扩展。
我正在慢慢将自己提升到 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++ 兼容,那么您不应依赖编译器的特定语言扩展。