【发布时间】:2021-07-13 17:38:03
【问题描述】:
以下最小示例因未初始化数组数据成员而被 Clang 和 GCC 拒绝:
class vector3
{
public:
constexpr vector3() = default;
private:
float m_data[3];
};
constexpr auto vec = vector3{};
这会产生相当直接的错误:
<source>:4:15: error: explicitly defaulted function 'constexpr vector3::vector3()' cannot be declared 'constexpr' because the implicit declaration is not 'constexpr':
4 | constexpr vector3() = default;
| ^~~~~~~
<source>:6:11: note: defaulted default constructor does not initialize 'float vector3::m_data [3]'
6 | float m_data[3];
| ^~~~~~
上述代码的目标是确保vector3 可以通过值初始化(例如vector3{})在常量表达式中使用,这将对子元素(m_data)进行零初始化。
错误是因为使用了constexpr关键字,解决方法就是去掉关键字,让default正确推断出这是否可以用在常量表达式中:
class vector3
{
public:
vector3() = default;
private:
float m_data[3];
};
constexpr auto vec = vector3{}; // now works?
奇怪的是,这实际上现在可以工作了 -- 并且仍然能够产生一个常量表达式,m_data 被零初始化,正如在 GCC 的程序集中可见(类似的存在于 Clang,但带有 XOR 指令):
vec:
.zero 12
我的问题是:= default 怎么可能产生一个(有效的)constexpr 构造函数,而 constexpr ... = default 由于它对constexpr 无效而失败? p>
这个问题似乎会影响 C++20 之前的 C++ 版本(C++11 到 C++17)。这在 C++20 中是否有所改变?
【问题讨论】:
-
The goal with the above code was to ensure that vector3 can be used in constant expressions via aggregate initialization一个简单的解决方案:struct vector3 { float m_data[3]; };可以在常量表达式中使用并且可以聚合初始化。或者:using vector3 = std::array<float, 3>; -
@eerorika 谢谢,但问题已经解释了
constexpr关键字是这里问题的原因,并且删除它仍然允许在常量表达式中对成员进行正确的值初始化;我只是询问为什么constexpr关键字是问题所在。还值得一提的是,以上只是一个最小的示例,对于构造更复杂的 OO 类,这些建议不是可行的替代方案,而不仅仅是对数组进行建模。 (编辑:我刚刚意识到当我的意思是“价值”时,我使用了“聚合初始化”这个词。抱歉有任何混淆!)。