Home > Backend Development > C++ > How does std::move() bind to lvalues when rvalue references are supposed to only bind to rvalues?

How does std::move() bind to lvalues when rvalue references are supposed to only bind to rvalues?

DDD
Release: 2024-11-14 10:46:01
Original
1034 people have browsed it

How does std::move() bind to lvalues when rvalue references are supposed to only bind to rvalues?

Unraveling the Mystery of std::move's Conversion Magic

When invoking std::move(), it's puzzling to observe that the referenced rvalue parameter can be bound to lvalues, which are typically restricted from attaching to rvalue references. Delving into the implementation of std::move() reveals the key to this apparent paradox.

Dissecting the std::move() Implementation

Beginning with the refined version of std::move():

template <typename T>
typename remove_reference<T>::type&& move(T&& arg) {
  return static_cast<typename remove_reference<T>::type&&>(arg);
}
Copy after login

Case 1: Invoking move() with Rvalues

When move() is employed with rvalues, such as a temporary object:

Object a = std::move(Object()); // Object() is temporary, hence prvalue
Copy after login

The resulting template instantiation is:

remove_reference<Object>::type&& move(Object&& arg) {
  return static_cast<remove_reference<Object>::type&&>(arg);
}
Copy after login

Since remove_reference transforms T& into T or T&& into T, and Object is a plain value, the final function morphology becomes:

Object&& move(Object&& arg) {
  return static_cast<Object&&>(arg);
}
Copy after login

The cast is crucial since named rvalue references are treated as lvalues.

Case 2: Invoking move() with Lvalues

When move() is invoked with lvalues:

Object a; // a is an lvalue
Object b = std::move(a);
Copy after login

The resulting move() instantiation is:

remove_reference<Object&>::type&& move(Object& && arg) {
  return static_cast<remove_reference<Object&>::type&&>(arg);
}
Copy after login

Again, remove_reference translates Object& to Object, yielding:

Object&& move(Object& && arg) {
  return static_cast<Object&&>(arg);
}
Copy after login

The Essence of Reference Collapsing

Understanding Object& && and its ability to bind to lvalues is the key to unlocking the enigma. C 11 introduces special rules for reference collapsing, which dictate:

Object & && = Object &
Object & &&& = Object &
Object && & = Object &
Object && &&& = Object &&
Copy after login

Thus, Object& && actually translates to Object&, a typical lvalue reference that effortlessly binds to lvalues.

The Resultant Function

With these rules in play, the final function becomes:

Object&& move(Object& arg) {
  return static_cast<Object&&>(arg);
}
Copy after login

Mirroring the instantiation for rvalues, it casts its argument to an rvalue reference, thus ensuring uniform behavior.

The Importance of remove_reference

The purpose of remove_reference becomes apparent when examining an alternative function:

template <typename T>
T&& wanna_be_move(T&& arg) {
  return static_cast<T&&>(arg);
}
Copy after login

When instantiated with an lvalue:

Object& && wanna_be_move(Object& && arg) {
  return static_cast<Object& &&&>(arg);
}
Copy after login

applying reference collapsing rules reveals an unusable move-like function, returning lvalues for lvalue arguments. The culprit is the absence of remove_reference, which hinders the proper conversion to rvalue references.

The above is the detailed content of How does std::move() bind to lvalues when rvalue references are supposed to only bind to rvalues?. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template