https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87057

--- Comment #5 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Jonathan Wakely from comment #4)
> (In reply to Konstantin Kharlamov from comment #2)
> > (In reply to Jonathan Wakely from comment #1)
> > > That would require a lot of special-casing just for std::variant.
> > 
> > Well, I think, in place of std::variant there could be any struct-wrapper;
> 
> If you have an example with a simple struct then please show it, maybe we
> can improve that case. std::variant is hundreds of lines of complex
> metaprogramming, not a struct-wrapper.

Given:

#include <memory>

struct PacketErr {
  std::unique_ptr<char> failed_devices;
};

struct V
{
  PacketErr p;
};

V deserialize() {
  PacketErr ret;
  return {ret};
}

GCC says:

s.cc: In function 'V deserialize()':
s.cc:14:14: error: use of deleted function 'PacketErr::PacketErr(const
PacketErr&)'
14 |   return {ret};
   |              ^
s.cc:3:8: note: 'PacketErr::PacketErr(const PacketErr&)' is implicitly deleted
because the default definition would be ill-formed:
3 | struct PacketErr {
  |        ^~~~~~~~~
s.cc:3:8: error: use of deleted function 'std::unique_ptr<_Tp,
_Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = char; _Dp =
std::default_delete<char>]'
In file included from /home/jwakely/gcc/9/include/c++/9.0.0/memory:80,
                 from s.cc:1:
/home/jwakely/gcc/9/include/c++/9.0.0/bits/unique_ptr.h:394:7: note: declared
here
394 |       unique_ptr(const unique_ptr&) = delete;
    |       ^~~~~~~~~~

This seems pretty damn good.

As I said, the problem is that std::variant consists of hundreds of lines of
complex metaprogramming. When a variant<X,Y> can't be constructed from Y& the
failure happens deep inside a nested template metaprogram. It's very difficult
for the compiler to guess what outcome you expected and to print an error
explaining why that didn't happen.



> 
> > > N.B. If you just write "return ret;" it will compile fine. In general
> > > "return x;" is better than "return {x};" because it doesn't prevent NRVO.
> > 
> > Thanks, I prefer the `{x}` to just `x` because in the latter I'm being
> > explicit that the `x` is not the type I'm returning, but there's some other
> > type that it's being wrapped to.
> 
> Which means you pessimize the code, because you force a copy, not an
> elidable move.
> 
> > As far as such trivial optimizations concerned, I'd prefer to rely on the
> > compiler figuring that out — in the end, that's why we don't write assembly,
> > right? =)
> 
> If you write "return ret;" the compiler is allowed to move from the
> variable, and is allowed to use the NVRO. It's not allowed to do that if you
> write "return {ret};".

Reply via email to