error: use of deleted function operator=(&&) with std::optional

456 Views Asked by At

I got myself an error sprouting from std::optional. Now when trying to reconstruct it, there seems to be something going on with defaulted ctors that I don't yet understand. Consider the following abstracted example:

I'm assigning a config struct that is taken up by the constructor of a static allocated optional. This works fine until I'm playing around with the move constructors.

Demo

#include <cstring>
#include <cstdio>
#include <memory>
#include <memory_resource>
#include <optional>

struct entity_options
{
    int a = 5;
};

struct entity
{
    entity(const entity_options& opts)
        :   opts_{ opts }
    { }

    virtual ~entity() {}

    // implicit declaration // -- works
    // entity(entity&&) = delete; // -- doesn't work
    entity(entity&&) = default; // -- also doesn't work wtf?

    entity_options opts_;
};

std::optional<entity> g_e;

int main()
{

    g_e = entity_options{
        .a = 4,
    };
}

It works if I just implicitely leave the complier declare my move ctor. When I delete it it doesn't work understandably, as optional seems to require move constructibility. However what surprises me is that it also doesn't work when I explicitely default it? I always thought this would yield the same result as implicitely having it declared by the compiler, yet the compiler disagrees:

<source>:34:5: error: use of deleted function 'std::optional<entity>& std::optional<entity>::operator=(std::optional<entity>&&)'
   34 |     };
      |     ^
In file included from <source>:5:
/opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/optional:663:11: note: 'std::optional<entity>& std::optional<entity>::operator=(std::optional<entity>&&)' is implicitly deleted because the default definition would be ill-formed:
  663 |     class optional
      |           ^~~~~~~~
/opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/optional:663:11: error: use of deleted function 'std::_Enable_copy_move<false, false, true, false, _Tag>& std::_Enable_copy_move<false, false, true, false, _Tag>::operator=(std::_Enable_copy_move<false, false, true, false, _Tag>&&) [with _Tag = std::optional<entity>]'
In file included from /opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/optional:43,
                 from <source>:5:
/opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/bits/enable_special_members.h:260:5: note: declared here
  260 |     operator=(_Enable_copy_move&&) noexcept                         = delete;
      |     ^~~~~~~~
ASM generation compiler returned: 1
<source>: In function 'int main()':

The reason I'm asking this is that in my production code the compiler seems to eagerly implictely delete my move constructors and I wanted to reassure him with =default that he's safe to go ahead and instantiate them as he pleases. But it still complains and I believe this is for the same reason.

My Hypothesis: By declaring it as defaulted, the compiler might still be free to delete it instead. This would however beg the question why he isn't doing that in the implicit case. Or to be more precise: Why is the default definition even ill-formed?

0

There are 0 best solutions below