The following code would not compile:
#include <utility>
class Foo{
public:
Foo(const Foo& foo) = delete;
explicit Foo(Foo&& foo) = default;
Foo() = default;
Foo bar(){
Foo foo;
return foo;
}
};
with the compiler message of:
test_rand.cpp:10:16: error: use of deleted function ‘Foo::Foo(const Foo&)’
10 | return foo;
| ^~~
test_rand.cpp:5:5: note: declared here
5 | Foo(const Foo& foo) = delete;
| ^~~
Thinking that this is because the copy constructor is deleted, and when the function return a temporary variable needs to be created, I added std::move to make foo a rvalue so that the move constructor can be called.
#include <utility>
class Foo{
public:
Foo(const Foo& foo) = delete;
explicit Foo(Foo&& foo) = default;
Foo() = default;
Foo bar(){
Foo foo;
return std::move(foo);
}
};
However, the compiler gives me the exact same error "use of deleted function 'Foo::Foo(const Foo&)'."
I then tried to remove the explicit keyword for the move constructor, and everything worked, even without the std::move
I wonder what the internal mechanism is for this. Specifically, what are the detailed steps for the compiler to return that value with only a move constructor, and what implicit conversions happen in the return process?
With the explicit keyword kept, I also found that if I changed the return line to return Foo(std::move(foo)), the error disappeared. But what is the difference between this and return std::move(foo), considering both of them are rvalues. And if I want to keep the move constructor explicit, is there a better way of doing so?
return Foo(std::move(foo));, wouldn't you?std::move(foo), since they're all rvalues.std::move(foo)will treat foo as an lvalue reference as it has a name and attempt to convert it to an rvalue. Theexplicitprevents the conversion.