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};".