';常数';限定符是否保证变量是常量表达式? 据我所知,C++中的 const 限定符基本上声明了内部链接,有时它允许变量用作常量表达式,以便将其放在数组边界、切换实例等中。

';常数';限定符是否保证变量是常量表达式? 据我所知,C++中的 const 限定符基本上声明了内部链接,有时它允许变量用作常量表达式,以便将其放在数组边界、切换实例等中。,c++,constexpr,constant-expression,C++,Constexpr,Constant Expression,但显然情况并非总是如此,我不知道如何正确使用const和constepr 具体地说,我发现在数组边界中使用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 initialize

但显然情况并非总是如此,我不知道如何正确使用
const
constepr

具体地说,我发现在数组边界中使用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

在后面的部分中,使用
constepr
而不是
const
解决了这个问题。但为什么最后一句话是无效的?一个表达式保持不变到底需要什么呢?

它完全符合标准

在后面的部分中使用constexpr而不是const解决了这个问题

因为constexpr在编译时计算值

但为什么最后一句话是无效的

const int bar[5] = {1, 2, 3, 4, 5}; 
表示条形图中的值是在运行时计算的常量值

在这里,您将在编译时进行此检查。所以const抛出了错误。使用constexpr可以在编译时对其进行推断时对其进行求解

那么,一个表达式是常数需要什么呢

将const声明为表达式会告诉编译器将该值视为const,并且不允许程序员修改它。const和constexpr都可以达到这个目的,但声明会使编译器将初始化延迟到运行时。当编译器在编译时检查int arr[bar[2]中的const值时,它抛出了一个错误


在变量声明中,
const
constexpr
的唯一含义相同的时间是当变量为整型或枚举型时。此外,此变量声明的初始值设定项必须是常量表达式。e、 g

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
它的元素也不是
constexpr
,因此它们不能用作数组绑定

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


那么,一个表达式是常数需要什么呢

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

规则是:

表达式E是一个核心常量表达式,除非按照抽象机器的规则([intro.execution])对E的求值将求值下列之一:


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

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

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

相反,对于纯整数类型
const
constepr
声明都被视为常量

这是由于语言规则

如果您查看
constintbar[5]={1,2,3,4,5}生成的汇编代码
constexpr int bar[5]={1,2,3,4,5},,
可以看出它们是一样的。所以从技术上来说,两者都应该起作用


因此,这验证了语言规则的局限性,正如其他一些答案所述,语言规则有一些历史原因。

这就是const和constexpr之间的微妙区别。只有第二个是针对编译器的,它告诉编译器这不仅是一个常量,而且可以在编译时计算,因此可以像#define或literal常量一样使用。简单常量可以在运行时计算,并且只是保证以后该值不会再次更改。但是由于历史原因,
const
整数值被允许作为数组边界。@john:不是真的-
const int N=rand()
是有效的,但不能用作数组边界。数组边界必须是
constepr
值。然而,出于历史原因,当使用这样一个
constepr
值初始化时,使用
const
整数变量是可以接受的。标准是如何将其形式化的?@Evg它稍微间接,但是我们一起正式讨论一下规则。@morimn
int
数组的元素肯定是
int
类型,你说得对。这只是关于<代码> const <代码>变量的规则,a <代码> conxPRP< /Cuff>变量非常严格,它不适用于 INT[]/Cord>,即使它适用于<代码> int >代码> .@ Mrimn:“const int”从1998以来的第一个标准就已经在C++中了。偶数
const int n=42
不能用作常量表达式(例如,结构成员的数组大小,即使在C99中也不允许VLA)。C通过让你使用预处理器来“处理它”。对C++模板(如代码> STD::数组< /Cord>)可用最小的改变是可用的,C++从C++开始以来就有了,“莫里姆。我没有投票,但看起来像。
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