constexpr 结构成员初始化
constexpr struct member initialisation
此代码编译:
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
,例如。来自 clang:
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:
产生的
An expression e
is a core constant expression unless the evaluation of e
, following the rules of the abstract
machine (4.6), would evaluate one of the following expressions:
...
(2.3) — an invocation of an undefined constexpr function or an undefined constexpr constructor;
怎么会是undefined,调用的时候明明是在定义之后?
问题是,成员函数定义被延迟到 最外层封闭 class 的右大括号(因为它们可以看到封闭 class 的成员es)。考虑这个 class 定义:
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;
};
假设这应该有效,实施过程如何处理这个定义?
Bar::get_one
里面的one
指的是Foo::one
,而不是::one
,所以一定是看到那个成员后才处理。它用在 two
的定义中,它是 constexpr,因此它必须在该成员的初始化程序之前处理。所以要让它起作用,总的顺序必须是 one
,然后是 get_one
,然后是 two
。
但是 C++ 实现不是这样工作的。他们不做任何复杂的依赖分析。它们按照可见的顺序处理声明和定义,[class.mem] §2 中列出了一些例外情况。
我似乎无法在标准中明确提及 constexpr 成员函数被视为未定义,直到 oitermost 封闭 class 完成,但这是唯一合乎逻辑的可能性。它不能以任何其他方式工作。
此代码编译:
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
,例如。来自 clang:
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:
产生的An expression
e
is a core constant expression unless the evaluation ofe
, following the rules of the abstract machine (4.6), would evaluate one of the following expressions:...
(2.3) — an invocation of an undefined constexpr function or an undefined constexpr constructor;
怎么会是undefined,调用的时候明明是在定义之后?
问题是,成员函数定义被延迟到 最外层封闭 class 的右大括号(因为它们可以看到封闭 class 的成员es)。考虑这个 class 定义:
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;
};
假设这应该有效,实施过程如何处理这个定义?
Bar::get_one
里面的one
指的是Foo::one
,而不是::one
,所以一定是看到那个成员后才处理。它用在 two
的定义中,它是 constexpr,因此它必须在该成员的初始化程序之前处理。所以要让它起作用,总的顺序必须是 one
,然后是 get_one
,然后是 two
。
但是 C++ 实现不是这样工作的。他们不做任何复杂的依赖分析。它们按照可见的顺序处理声明和定义,[class.mem] §2 中列出了一些例外情况。
我似乎无法在标准中明确提及 constexpr 成员函数被视为未定义,直到 oitermost 封闭 class 完成,但这是唯一合乎逻辑的可能性。它不能以任何其他方式工作。