c++ - 为什么枚举值的 initializer_list 不被视为常量表达式?
问题描述
在以下代码中(在本地和 Wandbox 上测试):
#include <iostream>
enum Types
{
A, B, C, D
};
void print(std::initializer_list<Types> types)
{
for (auto type : types)
{
std::cout << type << std::endl;
}
}
int main()
{
constexpr auto const group1 = { A, D };
print(group1);
return 0;
}
MSVC 15.8.5 无法编译:
error C2131: expression did not evaluate to a constant
note: failure was caused by a read of a variable outside its lifetime
note: see usage of '$S1'
(均指包含 的行constexpr
)
Clang 8 (HEAD) 报告:
error: constexpr variable 'group1' must be initialized by a constant expression
constexpr auto const group1 = { A, D };
^ ~~~~~~~~
note: pointer to subobject of temporary is not a constant expression
note: temporary created here
constexpr auto const group1 = { A, D };
^
gcc 9 (HEAD) 报告:
In function 'int main()':
error: 'const std::initializer_list<const Types>{((const Types*)(&<anonymous>)), 2}' is not a constant expression
18 | constexpr auto const group1 = { A, D };
| ^
error: could not convert 'group1' from 'initializer_list<const Types>' to 'initializer_list<Types>'
19 | print(group1);
| ^~~~~~
| |
| initializer_list<const Types>
为什么?
首先,他们显然都认为 enum-ids 是非常量的,尽管它们显然实际上是众所周知的编译时常量值。
其次,MSVC 抱怨 read outside 生命周期,但生命周期group1
及其值应该在print
.
第三,gcc 有一个奇怪的 const-vs-non-const 抱怨,我无法理解,因为初始化列表总是 const。
最后,除了 gcc 之外的所有代码都将愉快地编译和运行这段代码,如果constexpr
被删除的话,没有任何问题。当然,在这种情况下没有必要,但我看不出有什么好的理由让它不起作用。
同时 gcc 只会在参数类型更改为std::initializer_list<const Types>
-- 的情况下编译和运行代码,并且进行此更改会导致它在 MSVC 和 clang 中都无法编译。
(有趣的是:gcc 8,随着参数类型的改变,成功编译并运行了包括 在内的代码constexpr
,其中 gcc 9 出错了。)
FWIW,将声明更改为:
constexpr auto const group1 = std::array<Types, 2>{ A, D };
是否在所有三个编译器上编译和运行。因此initializer_list
,行为不端的可能是它本身,而不是枚举值。但是语法更烦人。(使用合适的make_array
实现会稍微不那么烦人,但我仍然不明白为什么原始版本无效。)
constexpr auto const group1 = std::array{ A, D };
也可以使用,这要归功于 C++17 模板归纳。虽然现在print
不能接受initializer_list
; 它必须在通用容器/迭代器概念上进行模板化,这很不方便。
解决方案
推荐阅读
- node.js - 发生错误 提供的有效负载无效。没有 JSON 对象可以被解码 Coinbas
- snaplogic - 在 snaplogic 中解析时如何检查 Excel 文件中是否存在列
- c# - 有没有办法将 CommandFlags 添加到辅助函数中?
- simulation - 如何在 SUMO 中建模出租车,以便人们只在不太远的情况下选择它
- c# - C# RabbitMQ 为什么第二个工人不接工作?
- java - 如何使用 stashboard 创建仪表板状态应用程序?
- c# - JustMock SQL 插入检查外键
- node.js - 如何在 node-fetch 中设置内容类型
- html - 冲突的 OL 和 UL ::before 选项
- python - 如何解决我的 python 代码(数组和绘图)中的问题?