Search code examples
c++c++20gcc11

Brace initialization when move constructor is deleted


This is probably not specific to C++20, but that's what I'm using right now. I have a simple struct

struct foo {
    int bar;
}

which can be declared and initialized as

const auto baz = foo{42};

Now, when I disable the move constructor (foo(foo&&) = delete;), the above initialization fails with

error: no matching function for call to ‘foo::foo()’

What's the reason for getting this error and is there a way to bring back the default behavior?


Solution

  • It is specific to C++20. Since C++20 a class is no longer aggregate if it there is any user-declared constructor at all, even if it is only defaulted or deleted. Aggregate initialization won't work anymore.

    This is a backwards-compatibility breaking change and you can't really get back the old behavior. You will have to adjust your code to the change.

    If you want to disable the move constructor, you need to add a proper constructor to use for the initialization, i.e. one taking an int as argument and initializing bar with it, and you can't rely on aggregate initialization anymore. Alternatively you can add a non-movable member with default initializer as last member of the class. Then it won't be required to be provided an initializer in the aggregate-initialization, but will make the whole class non-movable.

    It is however a bit surprising that you need to disable the move constructor manually at all. If the class is aggregate without any declared constructors it will be movable if and only if all its contents are movable. That should usually be the expected behavior as an aggregate class just lumps together the individual members without adding any further class invariants.