Search code examples
c++constructorlanguage-lawyerconsteval

Must consteval constructor initialize all data members?


In the next program struct B has immediate consteval default constructor, which does not initialize i field. Then this constructor is used to make a temporary and its i field remains untouched:

struct B {
    bool b = true;
    int i;
    consteval B() {}
};

static_assert( B{}.b );

Clang and MSVC are fine with it. But GCC complains:

 error: 'B{true}' is not a constant expression
    7 | static_assert( B{}.b );
      |                  ^
error: 'B()' is not a constant expression because it refers to an incompletely initialized variable

Demo: https://gcc.godbolt.org/z/x4n6ezrhT

Which compiler is right here?

Update:

I reported this issue to GCC: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104512 And it was closed with the explanation

This gives the hint that both MSVC and clang are incorrect really. EDG also implements correctly static_assert not being an immediate function context.


Solution

  • From cppreference's consteval specifier (since C++20):

    The consteval specifier declares a function or function template to be an immediate function,
    ...
    An immediate function is a constexpr function, and must satisfy the requirements applicable to constexpr functions or constexpr constructors, as the case may be.

    And if we go to cppreference's constexpr specifier (since C++11):

    A constexpr function must satisfy the following requirements:
    ...
    A constexpr constructor whose function body is not =delete; must satisfy the following additional requirements:
    ...
    for the constructor of a class or struct, every base class sub-object and every non-variant non-static data member must be initialized.

    However, as @user17732522 accurately pointed out in a comment below, this last requirement applies only until C++20.

    So I would say i doesn't need to be initialized in this case (Clang/MSVC are correct, gcc is wrong).