0

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?

glades
  • 3,778
  • 1
  • 12
  • 34
  • 3
    A constructor taking in `&&` is not the same as `operator=(&&)`. When you explicitly default it, the auto generated operator is no longer auto generated. – ChrisMM Mar 14 '23 at 13:31
  • @ChrisMM if I'm not mistaken it does complain about the ctor but indirectly. The type_trait for operator=(&&) evaluates to false bc. the class object can't be move constructed from the temporary that is entity_options. I didn't know that operator=(&&) of entity will cease to be autogenerated though. Explicitely redeclaring it works! I'm still wondering as I thought C++17 copy elision would come into play here and just skip copy/move operators entirely as the righthandside is a prvalue. – glades Mar 14 '23 at 13:37
  • @glades the reason why move-ctor and move assignment were disabled was because you wrote custom deleter. – ALX23z Mar 14 '23 at 13:43
  • 1
    Howard Hinnant has a [table](https://howardhinnant.github.io/smf.jpg) that shows which compiler generated functions get suppressed when a user-declared (including `=default` and `=delete`) function is provided. – Eljay Mar 14 '23 at 15:16

0 Answers0