2017-08-29 65 views
17

考虑下面的代码段:C++常量和聚集体内部功能体与外

#include <iostream> 
using namespace std; 

int main() 
{ 
    int x = 3; 
    const int i[] = { 1, 2, 3, 4 }; 
    float f[i[3]]; 
    struct S { int i, j; }; 
    const S s[] = { { 1, 2 }, { 3, 4 } }; 
    double d[s[1].j]; 
} 

它运行而不会出现错误。但是,以下内容:

#include <iostream> 
using namespace std; 


int x = 3; 
const int i[] = { 1, 2, 3, 4 }; 
float f[i[3]]; // error: array bound is not an integer constant before ']' token| 
struct S { int i, j; }; 
const S s[] = { { 1, 2 }, { 3, 4 } }; 
double d[s[1].j]; // error: array bound is not an integer constant before ']' token| 

int main() 
{ 
    return 0; 
} 

不会,因为它会获取突出显示为注释的错误。任何人都可以向我解释为什么这是?

+2

我认为这是因为我[3]不是常量,常量是我[]它意味着我[]不能指向任何其他块的内存,但你仍然可以改变我内的每个元素。 – apalomer

+2

一个猜测是你使用g ++ [它有一个扩展的VLA](https://stackoverflow.com/questions/5947661/in-c-books-array-bound-must-be-constant-expression-but-why -the-following-cod)并且不需要局部数组边界是恒定的。 –

+1

请注意,第一个在标准C++中也是无效的,但是您的编译器允许它作为扩展。 –

回答

18

很可能,编译器在函数中允许它的原因是由于编译器扩展:可变长度数组。它们允许在函数内声明的数组具有非constexpr长度。但它只能在内部工作,不在全局范围。

16

你必须使用constexpr,而不是const

constexpr int i[] = { 1, 2, 3, 4 }; 
constexpr S s[] = { { 1, 2 }, { 3, 4 } }; 

const适用于变量,并防止他们在你的代码被修改。

constexpr告诉该表达式在一个编译时间常数值导致编译器,因此它可以在地方使用像阵列长度,为什么它编译分配为const变量等

原因在功能上是VLA。它不可能在全球范围内宣布VLA。

6.7.6.2数组声明

2 If an identifier is declared as having a variably modified type, it shall be an ordinary identifier (as defined in 6.2.3), have no linkage, and have either block scope or function prototype scope. If an identifier is declared to be an object with static or thread storage duration, it shall not have a variable length array type.

而且VLA s为不是标准,其唯一的编译器扩展这儿的一部分。

+7

尽管这是一个完美有效的解决方案,但它并不能解释编译器错误。 –

+2

这不是因为在函数内部使用相同的构造时才起作用。 –

+0

不是down的投票人,但一个问题是一个常规的'const int' [可以用于数组大小](http://coliru.stacked-crooked.com/a/b82c88add207cc84)。这使答案有点棘手。我倾向于与尼科尔在这方面,扩展只是有一些限制,其中一个是无法使用和数组元素。 – NathanOliver