Maison >développement back-end >C++ >Comment std::move() se lie-t-il aux lvalues ​​alors que les références rvalue sont censées se lier uniquement aux rvalues ​​?

Comment std::move() se lie-t-il aux lvalues ​​alors que les références rvalue sont censées se lier uniquement aux rvalues ​​?

DDD
DDDoriginal
2024-11-14 10:46:011035parcourir

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

Percer le mystère de la magie de conversion de std::move

Lors de l'invocation de std::move(), il est déroutant d'observer que le Le paramètre rvalue peut être lié aux lvalues, qui ne peuvent généralement pas être attachées aux références rvalue. Plonger dans l'implémentation de std::move() révèle la clé de cet apparent paradoxe.

Disséquer l'implémentation de std::move()

Commencer par l'implémentation raffinée version de std::move():

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

Cas 1 : Invocation de move() avec Rvalues

Lorsque move() est utilisé avec des rvalues, comme un objet temporaire :

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

L'instanciation du modèle résultant est :

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

Depuis remove_reference transforme T& en T ou T&& en T, et Object est une valeur simple, la morphologie finale de la fonction devient :

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

Le cast est crucial puisque les références rvalue nommées sont traitées comme des lvalues.

Cas 2 : Invocation de move() avec Lvalues

Lorsque move() est invoqué avec des lvalues :

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

L'instanciation move() résultante est :

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

Encore une fois, remove_reference traduit Object& en Object, ce qui donne :

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

L'essence de l'effondrement des références

Comprendre l'objet& && et sa capacité à se lier aux valeurs l est la clé pour résoudre l’énigme. C 11 introduit des règles spéciales pour la réduction des références, qui dictent :

Object & && = Object &
Object & &&& = Object &
Object && & = Object &
Object && &&& = Object &&

Ainsi, Object& && se traduit en fait par Object&, une référence lvalue typique qui se lie sans effort aux lvalues.

Le Fonction résultante

Avec ces règles en jeu, la fonction finale devient :

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

En reflétant l'instanciation des rvalues, il convertit son argument en une référence rvalue, garantissant ainsi un comportement uniforme.

L'importance de remove_reference

Le but de remove_reference devient évident lors de l'examen d'une fonction alternative :

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

Quand instancié avec une lvalue :

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

l'application de règles de réduction de référence révèle une fonction de type déplacement inutilisable, renvoyant des lvalues ​​pour les arguments lvalue. Le coupable est l'absence de remove_reference, qui entrave la conversion correcte en références rvalue.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn