c++ - constexpr 结构成员初始化
问题描述
此代码编译:
struct Info
{
constexpr Info(bool val) : counted(false), value(unsigned(val)) {}
constexpr Info(unsigned val) : counted(true), value(val) {}
bool counted;
unsigned value;
};
constexpr const auto data = std::array{
Info{true}, Info{42u}
};
struct Foo
{
constexpr static inline const auto data = std::array{
Info{true}, Info{42u}
};
};
此代码不会:
struct Foo
{
struct Info
{
constexpr Info(bool val) : counted(false), value(unsigned(val)) {}
constexpr Info(unsigned val) : counted(true), value(val) {}
bool counted;
unsigned value;
};
constexpr static inline const auto data = std::array{
Info{true}, Info{42u}
};
};
报告的错误(在 MSVC、gcc 和 clang 中)表明他们认为Info
构造函数未定义或未定义constexpr
,例如。来自铿锵声:
prog.cc:21:5: note: undefined constructor 'Info' cannot be used in a constant expression
Info{true}, Info{42u}
^
为什么?
(可能与这个问题有关,但Info
在使用时应该是完整的;只是Foo
仍然不完整。)
解决方案
gcc-8 的错误信息可以说更清楚:
constexpr Foo::Info::Info(bool)’ called in a constant expression before its definition is complete
似乎错误是根据 [expr.const] §2 产生的:
一个表达式
e
是一个核心常量表达式,除非根据e
抽象机 (4.6) 的规则,对 的求值将求值以下表达式之一:...
(2.3) — 调用未定义的 constexpr 函数或未定义的 constexpr 构造函数;
当调用明确在定义之后时,为什么它是未定义的?
问题是,成员函数定义被延迟到最外面的封闭类的右大括号(因为它们可以看到封闭类的成员)。考虑这个类定义:
constexpr int one = 1;
struct Foo
{
struct Bar
{
static constexpr int get_one() { return one; }
};
static constexpr int two = Bar::get_one() + 1;
static constexpr int one = 42;
};
假设这应该可行,实现如何处理这个定义?
one
insideBar::get_one
指的是Foo::one
, not ::one
,因此必须在看到该成员后对其进行处理。它用于two
constexpr 的定义中,因此必须在该成员的初始化程序之前对其进行处理。因此,要使其起作用,总体顺序必须是one
,然后get_one
,然后two
。
但是 C++ 实现不是这样工作的。他们不做任何复杂的依赖分析。它们按照被看到的顺序处理声明和定义,[class.mem] §2 中列出了一些例外情况。
在最接近的封闭类完成之前,我似乎无法在标准中明确提及 constexpr 成员函数被认为是未定义的,但这是唯一合乎逻辑的可能性。它不能以任何其他方式工作。
推荐阅读
- machine-learning - 重函数(单位/阶跃函数)导数
- javascript - 如何返回状态 500 并停止运行该路线的脚本
- javascript - JavaScript DOM - 如何允许用户只选择一个选项
- gstreamer - 从 DVD 中提取字幕
- video - 我正在使用以下代码将 YouTube 视频转换为音频,但尽管安装了 ffmpeg,但仍出现错误
- c++ - 使用模板特化写入两个输出流
- python - 从 Theano 1.0.0 切换到 TensorFlow 2.2(都使用 Keras)会导致损失呈指数级增长和准确性停滞不前
- python - 在累积图上指示地标
- ios - 如何根据日期选择器选择的时间对数据进行排序 在 Swift 5 中使用 Realm
- c# - 如何链接三元运算符?