如何解决'const' 限定符何时保证变量是常量表达式?
据我所知,C++ 中的 const
限定符基本上声明了内部链接,有时它允许将变量用作常量表达式,以便将其放入数组边界、切换案例等.
但显然情况并非总是如此,我不知道如何正确使用 const
和 constexpr
。
具体来说,我发现当在数组边界中使用 const 限定数组的元素时,它不会被视为常量表达式,如下面的代码所示。
const int N = 3;
int foo[N] = {1,2,3}; // Valid
const int bar[5] = {1,3,4,5};
int arr[bar[2]] = {1,3}; // Invalid because a VLA can't be initialized
在后面部分使用 constexpr
代替 const
可以解决问题。但是为什么最后一条语句无效呢?究竟需要什么才能使表达式保持不变?
解决方法
唯一一次 const
与变量声明中的 constexpr
含义相同,即变量是整数或枚举类型时。另外,这个变量声明的初始化器必须是一个常量表达式。例如
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
,但这会破坏现有代码,因此不会更改。
究竟需要什么才能使表达式保持不变?
这很有趣,因为该语言实际上并没有说明表达式需要什么才能成为常量表达式。相反,它假定 所有 表达式都是常量表达式,并提供一个条件列表,如果不满足这些条件,则表达式将不是常量表达式。
规则是here:
表达式 E 是核心常量表达式除非对 E 的求值,遵循抽象机 ([intro.execution]) 的规则,将求值以下之一:...
然后是一个条件列表,这些条件使表达式不是常量表达式。
,使用 const 声明 const int bar[5] = {1,2,3,4,5};
bar[2]
被视为变量而不是常量。
使用 constexpr 声明 constexpr int bar[5] = {1,5};
bar[2]
被视为预期的常量。
相反,对于纯整型,const
和 constexpr
声明都作为常量受到威胁。
这是因为语言规则。
对于 example,如果您查看为 const int bar[5] = {1,5};
和 constexpr int bar[5] = {1,5};
生成的汇编代码,
可以看出它们是相同的。所以从技术上讲,两者都行得通。
因此,这验证了限制来自语言规则,如其他一些答案所述,这些限制有一些历史原因。
,完全符合标准
在后面的部分使用 constexpr 而不是 const 可以解决问题。
因为 constexpr 在编译时计算值
但为什么最后一条语句无效?
const int bar[5] = {1,5};
表示 bar 中的值是在运行时计算的常量值
int arr[bar[2]] = {1,3};
在这里,您是在编译时进行此检查。所以 const 抛出错误。使用 constexpr 解决它,因为它在编译时推导它。
究竟需要什么才能使表达式保持不变?
向表达式声明 const 会告诉编译器将该值视为 const 并且不允许程序员修改它。 const 和 constexpr 都可以达到目的,但声明使编译器将初始化推迟到运行时。当编译器在编译时检查 int arr[bar[2]] 中的 const 值时,它会抛出错误。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。