web-dev-qa-db-fra.com

Quand utiliser std :: forward pour transmettre des arguments?

C++ 0x montre un exemple d'utilisation de std::forward:

template<class T>
void foo(T&& arg) 
{
  bar(std::forward<T>(arg));
}

Quand est-il avantageux d'utiliser std::forward, toujours?

En outre, il faut utiliser && dans la déclaration des paramètres, est-il valable dans tous les cas? Je pensais que vous deviez passer temporairement à une fonction si la fonction était déclarée avec && dedans, peut-on appeler foo avec n’importe quel paramètre?

Enfin, si j’ai un appel de fonction tel que celui-ci:

template<int val, typename... Params>
void doSomething(Params... args) {
  doSomethingElse<val, Params...>(args...);
}

Devrais-je utiliser ceci à la place:

template<int val, typename... Params>
void doSomething(Params&&... args) {
  doSomethingElse<val, Params...>(std::forward<Params>(args)...);
}

De même, si vous utilisez les paramètres deux fois dans la fonction, c’est-à-dire que vous transférez deux fonctions en même temps, il est judicieux d’utiliser std::forward? Ne veut pas std::forward convertir deux fois la même chose en une pièce 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 par std::forward, et j'utiliserais volontiers un peu de nettoyage.

147
coyotte508

Utilisez-le comme votre premier exemple:

template <typename T> void f(T && x)
{
  g(std::forward<T>(x));
}

template <typename ...Args> void f(Args && ...args)
{
  g(std::forward<Args>(args)...);
}

C'est à cause de règles de réduction de référence : Si T = U&, puis T&& = U&, mais si T = U&&, puis T&& = U&&, vous obtenez donc toujours le type correct dans le corps de la fonction. Enfin, vous avez besoin de forward pour reconvertir le x de lvalue (car il porte maintenant un nom!) Dans une référence rvalue, le cas échéant.

Vous ne devez toutefois pas transmettre quelque chose plus d'une fois, car cela n'a généralement aucun sens. Le fait de transférer signifie que vous êtes potentiellement en train de déplacer l'argument de bout en bout. à l'appelant final, et une fois qu'il a été déplacé, il est parti, vous ne pouvez donc plus l'utiliser (de la manière que vous aviez probablement l'intention de faire).

116
Kerrek SB