【问题标题】:C++ Constants and aggregates inside function body vs. outside函数体内部与外部的 C++ 常量和聚合
【发布时间】:2018-02-07 09:10:08
【问题描述】:

考虑以下代码:

#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;
}

没有,因为它会获取以 cmets 突出显示的错误。谁能给我解释一下这是为什么?

【问题讨论】:

  • 我认为是因为 i[3] 不是常数,常数是 i[] 这意味着 i[] 不能指向任何其他内存块,但您仍然可以更改每个i 中的元素。
  • 一种猜测是您使用 g++ which has an extension for VLAs 并且不需要本地数组边界是恒定的。
  • 请注意,第一个在标准 C++ 中也是无效的,但您的编译器允许它作为扩展。
  • 第一个例子我收到很多警告。
  • 使用正确的编译器设置,第一个代码示例也将无法编译 src/test.cpp:在函数“int main()”中:src/test.cpp:8:17:错误:ISO C++ 禁止变长数组'f' [-Werror=vla] float f[i[3]];

标签: c++ compiler-errors compilation constants


【解决方案1】:

你必须使用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 如果一个标识符被声明为具有可变修改类型,它 应为普通标识符(如 6.2.3 中定义),没有 链接,并且具有块范围或函数原型范围。如果 标识符被声明为具有静态或线程的对象 存储时长,不能是变长数组类型。

另外,VLAs 不是 标准的一部分,它是这里唯一的编译器扩展。

【讨论】:

  • 虽然这是一个完全有效的解决方案,但它并不能解释编译器错误。
  • 这不是因为在函数内部使用相同的构造。
  • 不是反对票,但有一个问题是普通的const intcan be used for an array size。这使得答案有点棘手。我倾向于在这方面与 Nicol 合作,并且扩展只是有一些限制,其中之一是无法使用和数组元素。
  • 虽然你确实说它在函数中编译的原因是VLA。不可能在全局范围内声明 VLA。 所以 IDK。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-02
    • 2012-03-28
    相关资源
    最近更新 更多