C ++ 0x montre un exemple d'utilisation std::forward
:
template<class T>
void foo(T&& arg)
{
bar(std::forward<T>(arg));
}
Quand est-il toujours avantageux de l'utiliser std::forward
?
En outre, il nécessite de l'utiliser &&
dans la déclaration des paramètres, est-ce valable dans tous les cas? Je pensais que vous deviez passer des temporaires à une fonction si la fonction était déclarée avec &&
, alors peut-on appeler foo avec n'importe quel paramètre?
Enfin, si j'ai un appel de fonction comme celui-ci:
template<int val, typename... Params>
void doSomething(Params... args) {
doSomethingElse<val, Params...>(args...);
}
Dois-je utiliser ceci à la place:
template<int val, typename... Params>
void doSomething(Params&&... args) {
doSomethingElse<val, Params...>(std::forward<Params>(args)...);
}
De plus, si vous utilisez les paramètres deux fois dans la fonction, c'est-à-dire le renvoi vers deux fonctions en même temps, est-il judicieux d'utiliser std::forward
? La std::forward
même chose ne sera-t-elle pas convertie deux fois en temporaire, en déplaçant la mémoire et en la rendant invalide pour une deuxième utilisation? Le code suivant serait-il correct:
template<int val, typename... Params>
void doSomething(Params&&... args) {
doSomethingElse<val, Params...>(std::forward<Params>(args)...);
doSomethingWeird<val, Params...>(std::forward<Params>(args)...);
}
Je suis un peu confus std::forward
, et j'utiliserais volontiers quelques éclaircissements.
la source
Args...&& args
?La réponse de Kerrek est très utile, mais elle ne répond pas complètement à la question du titre:
Pour y répondre, il faut d'abord introduire une notion de références universelles . Scott Meyers a donné ce nom et de nos jours on les appelle souvent des références de transmission. En gros, quand vous voyez quelque chose comme ça:
gardez à l'esprit qu'il
param
ne s'agit pas d'une référence rvalue (comme on peut être tenté de le conclure), mais d'une référence universelle *. Les références universelles sont caractérisées par une forme très restreinte (justeT&&
, sans const ou qualificatifs similaires) et par une déduction de type - le typeT
sera déduit lors de l'f
appel. En un mot, les références universelles correspondent aux références rvalue si elles sont initialisées avec rvalues, et aux références lvalue si elles sont initialisées avec lvalues.Maintenant, il est relativement facile de répondre à la question initiale - appliquer
std::forward
à:Un exemple pour le premier cas:
Dans le code ci-dessus, nous ne voulons
prop
pas avoir de valeur inconnue après laother.set(..)
fin, donc aucun transfert ne se produit ici. Cependant, lors de l'appel,bar
nous avançonsprop
comme nous en avons terminé avec lui etbar
pouvons faire ce qu'il veut (par exemple, le déplacer).Un exemple pour le deuxième cas:
Ce modèle de fonction doit se déplacer
prop
dans la valeur de retour s'il s'agit d'une rvalue et la copier s'il s'agit d'une lvalue. Dans le cas où nous aurions omisstd::forward
à la fin, nousprop
créerions toujours une copie, ce qui est plus cher quand il s'agit d'une rvalue.* pour être tout à fait précis, une référence universelle est un concept de prise d'une référence rvalue à un paramètre de modèle non qualifié cv.
la source
Cet exemple vous aide-t-il? J'ai eu du mal à trouver un exemple non générique utile de std :: forward, mais je suis tombé sur un exemple de compte bancaire que nous transmettons l'argent à déposer en argument.
Donc, si nous avons une version const d'un compte, nous devrions nous attendre lorsque nous le passons à notre modèle de dépôt <> que la fonction const est appelée; et cela lève alors une exception (l'idée étant qu'il s'agissait d'un compte verrouillé!)
Si nous avons un compte non const, nous devrions pouvoir modifier le compte.
Construire:
Production attendue:
la source