'const' 限定符什么时候保证变量是常量表达式?

When does the 'const' qualifier guarantee the variable to be a constant expression?

据我所知,C++中的const限定符基本上声明了内部链接,有时它允许将变量用作常量表达式,以便可以将其放入数组边界,switch cases等

但显然情况并非总是如此,我不知道 constconstexpr 的正确用法。

具体来说,我发现当在数组边界中使用 const 限定数组的元素时,它不会被视为常量表达式,如以下代码所示。

const int N = 3;
int foo[N] = {1, 2, 3};  // Valid

const int bar[5] = {1, 2, 3, 4, 5};
int arr[bar[2]] = {1, 2, 3};  // Invalid because a VLA can't be initialized

后面用constexpr代替const就解决了问题。但是为什么最后一条语句无效呢?一个表达式究竟需要什么才能保持不变?

完全符合标准

后面用constexpr代替const就解决了问题

Because constexpr evaluates the value at compile time

但是为什么最后一条语句无效呢?

const int bar[5] = {1, 2, 3, 4, 5}; 

says that the values in bar are const values evaluated at run time


int arr[bar[2]] = {1, 2, 3};  

here you are making this check at compile time . so const is throwing error. Using constexpr solves it as it deduces it at the compile time.

表达式要保持不变究竟需要什么?

declaring const to an expression tells the compiler to treat that value as const and to not allow the programmer to modify it . both const and constexpr serves the purpose but declaring makes compiler to defer initialization until run time . As compiler is checking for const value in int arr[bar[2]] at compile time it's throwing an error.

只有在变量声明中constconstexpr意思相同的时候,是变量是整型或枚举类型。另外,这个变量声明的初始化器必须是常量表达式。例如

const int n = 42;       // same as constexpr
                        // type is int
                        // initializer is integer literal, which is constant expression

std::cin >> x;          // some user input
const int n = x;        // NOT constexpr
                        // because initializer is not a constant expression

const double n = 4.2;   // NOT constexpr
                        // type is not integral or enumeration type

您的最后一行代码无法编译,因为 bar 不是整型或枚举类型,因此它不是 constexpr。因为它不是 constexpr none 它的元素也是 constexpr,因此它们不能用作数组绑定。

这种整数特殊情况的原因是历史原因:数组边界需要是常量表达式,但在 C++11 之前,唯一的表达方式是 const int。从技术上讲,规则可以更改为 require 声明具有 constexpr 但这会破坏现有代码,因此不会更改。


And exactly what is required for an expression to be constant?

这很有趣,因为该语言实际上并没有说明表达式成为常量表达式的要求。相反,它假定 所有 表达式都是常量表达式,并提供一个条件列表,如果不满足这些条件将使表达式不是常量表达式。

规则是here:

An expression E is a core constant expression unless the evaluation of E, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following: ...

后面是使表达式不是常量表达式的条件列表。

使用 const 声明 const int bar[5] = {1, 2, 3, 4, 5}; bar[2] 被视为 变量 而不是常量。

使用 constexpr 声明 constexpr int bar[5] = {1, 2, 3, 4, 5}; bar[2] 按预期被视为 常量

相反,对于纯 整数类型 constconstexpr 声明都作为常量受到威胁。

这是由于语言规则。

对于 example 如果您查看为 const int bar[5] = {1, 2, 3, 4, 5};constexpr int bar[5] = {1, 2, 3, 4, 5}; 生成的汇编代码, 可以看出它们是相同的。所以从技术上讲,两者都可以工作。

所以这验证了限制来自语言规则,这有一些历史原因,如其他一些答案所述。