The following minimal example is rejected by both Clang and GCC for not initializing the array data-member:
class vector3
{
public:
constexpr vector3() = default;
private:
float m_data[3];
};
constexpr auto vec = vector3{};
Which yields the reasonably straight-forward error:
<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];
| ^~~~~~
The goal with the above code was to ensure that vector3 can be used in constant expressions via value-initialization (e.g. vector3{}), which will zero-initialize the sub-elements (m_data).
The error occurs due to the use of the constexpr keyword, and the fix is simply to remove the keyword and to allow default to correctly deduce whether this can be used in a constant expression:
class vector3
{
public:
vector3() = default;
private:
float m_data[3];
};
constexpr auto vec = vector3{}; // now works?
Curiously, this actually now works -- and is still able to produce a constant expression, with m_data being zero-initialized, as visible in the assembly for GCC (Similar exists in Clang, but with XOR instructions):
vec:
.zero 12
My question is: How is it possible that = default produces a (valid) constexpr constructor, whereas constexpr ... = default fails due to it not being valid for constexpr?
This question appears to affect C++ versions prior to C++20 (C++11 through C++17). Was this changed in C++20?