I want to know when copy/move elision applies (or is allowed to apply) to explicitly delete
d copy/move constructors and to non-delete
d copy/move constructors. Here are the specifics:
Can an explicitly
delete
d copy ctor or move ctor get elided? Is an attempt to construct an object from another same-type object or temporary object ever allowed to succeed by skipping over thedelete
d copy ctor and/ordelete
d move ctor?Here’s what happens in VC12 (with which I’m not sure if there is an option to disable copy/move elision):
#include <iostream> struct Foo { Foo() { std::cout << "default ctor\n"; } Foo(Foo const&) = delete; Foo(Foo&&) = delete; }; int main() { // ----Output------ Foo{ Foo() }; // "default ctor" Foo f; // "default ctor" Foo{ std::move(f) }; // error C2280: 'Foo::Foo(Foo &&)' : attempting to reference a deleted function Foo{ f }; // error C2280: 'Foo::Foo(const Foo &)' : attempting to reference a deleted function }
Even though IntelliSense complains about
Foo{ Foo() };
:Error: function “Foo::Foo(Foo &&)” ... cannot be referenced – it is a deleted function
, the compiler doesn't complain there, so that line still compiles.Why does
Foo{ Foo() };
work, but notFoo{ std::move(f) };
? If one call elides the move ctor, then shouldn’t the other?Why does
Foo{ Foo() };
work, but notFoo{ f };
? This selectivity looks arbitrary. This kind of arbitrary preference of rvalue reference over const reference (or vice versa) doesn’t seem to apply to non-ctor methods; where in a call, if adelete
d overload that would otherwise have a higher overload resolution priority than a non-delete
d overload, thedelete
d one blocks the non-delete
d one, resulting in a compiler error:struct Bar { void g(int const&) {} void g(int&&) = delete; }; //… Bar b; b.g(2); //error C2280: 'void Bar::g(int &&)' : attempting to reference a deleted function // ^ Would have compiled had function `g(int&&)` been commented out.
According to that logic, a
delete
dFoo(Foo&&)
shouldn’t block a call toFoo(Foo const&)
when the argument is not a temporary;Foo(Foo&&)
would have a lower overload resolution priority thanFoo(Foo const&)
in that case.I tried the same
Foo
example in g++ 4.8 with copy elision disabled (via the flag-fno-elide-constructors
) and again with it enabled. Both g++ trials gave:error: use of deleted function 'Foo::Foo(Foo&&)'
forFoo{ Foo() };
anderror: use of deleted function 'Foo::Foo(const Foo&)'
forFoo{ f };
Which compiler is correct?
Ms VC ++ has a very old well-known bug. From the C++ Standard