lurscher
lurscher

Reputation: 26943

r-value reference return type semantics?

Does a return type like this represent something meaningful in c++11?

template <typename R>
R&& grabStuff();

T instance = grabStuff<T>();

I would hope that grabStuff should throw a compile-time error if R does not have a move constructor, since this would seem to disallow the return type to use a copy constructor

Upvotes: 9

Views: 4125

Answers (3)

Cosyn
Cosyn

Reputation: 4987

If the return type of a function is an rvalue reference, then the result of the function call is an xvalue; if the return type is non-reference, then the result of the function call is a prvalue.

Both xvalue and prvalue are rvalues, there are some minor differences between them, more like differences between reference and non-reference. For example, an xvalue may have an incomplete type, while a prvalue shall usually have a complete type or the void type. When typeid is applied to an xvalue whose type is a polymorphic class type, the result refers to the dynamic type; and for prvalue, the result refers to the static type.

For your declaration statement T instance = grabStuff<T>();, if T is a class type, I think there is no difference between xvalue and prvalue in this context.

The initializer is an rvalue, so the compiler prefers a move constructor. But if no move constructor is declared, and a copy constructor with const reference parameter is declared, then this copy constructor will be chosen, and there is no error. I don't know why do you want this to be an error. If this is an error, any old code will be incorrect when copy-initialize some object from an rvalue.

Upvotes: 3

Kerrek SB
Kerrek SB

Reputation: 477080

As always, when returning references you must return a reference to something that's still alive after the function returns. How you do that is up to you. Example:

T global_thing;

T && get() { return std::move(global_thing); }

struct Foo { Foo(T &&); /* ... */ };

int main()
{
    global_thing.reset();
    Foo a(get());
    global_thing.reset();
    Foo b(get());
}

The more typical example for returning an rvalue reference is std::move itself, though, which returns a reference to the thing you pass into it (and thus it's the caller's responsibility to provide a valid input).

Upvotes: 8

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361482

It may be meaningful depending on what you want to do with it, and how you've implemented the function.

In fact, std::move return type is T&& (rvalue reference) which is meaningful, as it defines the very purpose of the existence of std::move in the C++11 library:

Upvotes: 1

Related Questions