I have a move-only struct
Foo
Foo get();
get
Foo
Foo&&
#include <iostream>
struct Foo
{
Foo(std::string s) : s(std::move(s)) {}
Foo(Foo&& f) : s(std::move(f.s)) {}
Foo(const Foo&) = delete;
Foo& operator=(const Foo&) = delete;
std::string s;
};
Foo get()
{
return Foo { "hello" };
}
int main()
{
// capture return value as l-value
Foo lv1 = get();
// move into another lvalue
Foo lv2 = std::move(lv1);
std::cout << lv2.s << '\n';
// capture return value as r-value reference
Foo&& rv1 = get();
// move into another lvalue
Foo lv3 = std::move(rv1);
std::cout << lv3.s << '\n';
return 0;
}
Foo lv1 = get();
This requires that Foo
is copy/moveable.
Foo&& rv1 = get();
This does not (at least, not as far as this line of code is concerned; the implementation of get
may still require one).
Even though compilers are permitted to elide the copy of the return value into the variable, copy initialization of this form still requires the existence of an accessible copy or move constructor.
So if you want to impose as few limitations on the type Foo
as possible, you can store a &&
of the returned value.
Of course, C++17 changes this rule so that the first one doesn't need a copy/move constructor.