常量表达式中具有未初始化成员的“默认”构造函数

2024-02-23

以下最小示例因未初始化数组数据成员而被 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];
      |           ^~~~~~

Live Example https://gcc.godbolt.org/z/Kvh8Wf3P3

上述代码的目标是确保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

Live Example https://gcc.godbolt.org/z/PYod6Y6z1

我的问题是:怎么可能= default产生一个(有效)constexpr构造函数,而constexpr ... = default由于无效而失败constexpr?


此问题似乎影响 C++20 之前的 C++ 版本(C++11 到 C++17)。 C++20 中对此进行了更改吗?

Live Example https://gcc.godbolt.org/z/38rGedeeE


是的,确实在 C++20 中,规则发生了变化,因此constexpr不再需要构造函数来初始化所有非静态成员和基类子对象。

在 C++20 之前,我们有一个有趣的情况,即您的构造函数无法声明constexpr,但对象vector3类型仍然可以在常量表达式中使用,因为在第一个声明中显式默认的默认构造函数实际上并不called在值初始化期间,除非它是不平凡的(C ++ 17 [dcl.init] / 8.2),因此禁止调用非constexpr常量表达式内的函数不会被触发。这不是编译器错误;而是编译器错误。这只是语言中的一个怪癖。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

常量表达式中具有未初始化成员的“默认”构造函数 的相关文章

随机推荐