Dean Seo
Dean Seo

Reputation: 5683

When do we practically need 'explicit xvalues'?

The definition of xvalue is as follows:

— An xvalue (an “eXpiring” value) also refers to an object, usually near the end of its lifetime (so that its resources may be moved, for example). An xvalue is the result of certain kinds of expressions involving rvalue references (8.3.2). [ Example: The result of calling a function whose return type is an rvalue reference is an xvalue. —end example ]

Will we ever fall into where we practically need to use a function whose return type is an rvalue reference, which is an xvalue?

const int && Foo()
{
    // ...
}

Move semantics take an rvalue reference as a parameter, not a return value. So I don't think that's the case.

Upvotes: 13

Views: 929

Answers (3)

Arne Mertz
Arne Mertz

Reputation: 24576

Returning rvalue references can be of use for functions that already take rvalues as parameters. A simple example:

struct X {
    X() = default;
    X(X&& other) { std::cout << "move ctor\n"; }
    X(X const&) = delete;
    void log(std::string const& s){ std::cout << "log: " << s << "\n"; }
};

void sink(X&& x) { 
    x.log("sink"); 
}

X&& passOn(X&& in) {
    in.log("pass");
    return std::move(in);
}

X moveOn(X&& in) {
    in.log("move");
    return std::move(in);
}

int main() {
    sink(passOn(X()));
    std::cout << "===============================\n";
    sink(moveOn(X()));
}

Live demo →

The second function will call the move constructor to create the returned object, while the first will pass on the reference it already got. This is more useful if we don't return the original reference but instead a reference to a part of the referred object, e.g.

template<class T>
T&& getHead(std::vector<T>&& input) {
    return std::move(input.front());
}

Upvotes: 5

sbabbi
sbabbi

Reputation: 11181

Will we ever fall into where we practically need to use a function whose return type is an rvalue reference, which is an xvalue?

It used in container classes, for instance tuple has a get overload that looks like this:

template< std::size_t I, class... Types >
typename std::tuple_element<I, tuple<Types...> >::type&&
    get( tuple<Types...>&& t );

I assume that std::optional and std::variant in C++17 will both have a similar overloads.

Granted, the only point is to avoid to type std::move in some very specific situations, like:

 auto x = std::get<1>( f() );

Where f returns a tuple by value.

Upvotes: 3

ixSci
ixSci

Reputation: 13698

That's exactly what std::move is — the result of std::move execution is an xvalue. Other than that it is hard to tell since in the main returning a reference from the function is a bad thing most of the time. But maybe someone will come up with another clever usage of such a function.

Upvotes: 5

Related Questions