Namespaces
Variants

std:: forward

From cppreference.net
Utilities library
Défini dans l'en-tête <utility>
(1)
template < class T >
T && forward ( typename std:: remove_reference < T > :: type & t ) noexcept ;
(depuis C++11)
(jusqu'à C++14)
template < class T >
constexpr T && forward ( std:: remove_reference_t < T > & t ) noexcept ;
(depuis C++14)
(2)
template < class T >
T && forward ( typename std:: remove_reference < T > :: type && t ) noexcept ;
(depuis C++11)
(jusqu'à C++14)
template < class T >
constexpr T && forward ( std:: remove_reference_t < T > && t ) noexcept ;
(depuis C++14)
1) Transfère les lvalues comme des lvalues ou des rvalues, selon T.

Lorsque t est une référence de transfert (un argument de fonction déclaré comme une référence à une valeur r vers un paramètre de modèle de fonction non qualifié cv), cette surcharge transfère l'argument à une autre fonction avec la catégorie de valeur qu'il avait lors du passage à la fonction appelante.

Par exemple, si utilisé dans un wrapper tel que le suivant, le modèle se comporte comme décrit ci-dessous :

template<class T>
void wrapper(T&& arg)
{
    // arg est toujours une lvalue
    foo(std::forward<T>(arg)); // Transfère comme lvalue ou comme rvalue, selon T
}
  • Si un appel à wrapper() passe une rvalue std::string , alors T est déduit en std::string (et non std::string& , const std::string& , ou std::string&& ), et std::forward garantit qu'une référence rvalue est passée à foo .
  • Si un appel à wrapper() passe une lvalue const std::string , alors T est déduit en const std::string& , et std::forward garantit qu'une référence lvalue const est passée à foo .
  • Si un appel à wrapper() passe une lvalue non-const std::string , alors T est déduit en std::string& , et std::forward garantit qu'une référence lvalue non-const est passée à foo .
2) Transfère les valeurs rvalue en tant que rvalues et interdit le transfert des rvalues en tant que lvalues.

Cette surcharge permet de transmettre le résultat d'une expression (tel qu'un appel de fonction), qui peut être une rvalue ou une lvalue, en conservant la catégorie de valeur originale d'un argument de référence de transfert.

Par exemple, si un wrapper n'effectue pas simplement un transfert de son argument, mais appelle une fonction membre sur l'argument, et transmet son résultat :

// wrapper de transformation
template<class T>
void wrapper(T&& arg)
{
    foo(forward<decltype(forward<T>(arg).get())>(forward<T>(arg).get()));
}

où le type de arg peut être

struct Arg
{
    int i = 1;
    int  get() && { return i; } // l'appel à cette surcharge est une rvalue
    int& get() &  { return i; } // l'appel à cette surcharge est une lvalue
};

Tenter de transmettre une rvalue en tant que lvalue, par exemple en instanciant la forme (2) avec un type référence lvalue T, constitue une erreur à la compilation.

Table des matières

Notes

Voir la déduction d'arguments de template pour les règles spéciales concernant les références de transfert ( T&& utilisé comme paramètre de fonction) et les références de transfert pour plus de détails.

Paramètres

t - l'objet à transmettre

Valeur de retour

static_cast < T && > ( t )

Complexité

Constante.

Exemple

Cet exemple démontre le transfert parfait des paramètres vers l'argument du constructeur de la classe T . Le transfert parfait des packs de paramètres est également démontré.

#include <iostream>
#include <memory>
#include <utility>
struct A
{
    A(int&& n) { std::cout << "rvalue overload, n=" << n << '\n'; }
    A(int& n)  { std::cout << "lvalue overload, n=" << n << '\n'; }
};
class B
{
public:
    template<class T1, class T2, class T3>
    B(T1&& t1, T2&& t2, T3&& t3) :
        a1_{std::forward<T1>(t1)},
        a2_{std::forward<T2>(t2)},
        a3_{std::forward<T3>(t3)}
    {}
private:
    A a1_, a2_, a3_;
};
template<class T, class U>
std::unique_ptr<T> make_unique1(U&& u)
{
    return std::unique_ptr<T>(new T(std::forward<U>(u)));
}
template<class T, class... U>
std::unique_ptr<T> make_unique2(U&&... u)
{
    return std::unique_ptr<T>(new T(std::forward<U>(u)...));
}
auto make_B(auto&&... args) // since C++20
{
    return B(std::forward<decltype(args)>(args)...);
}
int main()
{
    auto p1 = make_unique1<A>(2); // rvalue
    int i = 1;
    auto p2 = make_unique1<A>(i); // lvalue
    std::cout << "B\n";
    auto t = make_unique2<B>(2, i, 3);
    std::cout << "make_B\n";
    [[maybe_unused]] B b = make_B(4, i, 5);
}

Sortie :

rvalue overload, n=2
lvalue overload, n=1
B
rvalue overload, n=2
lvalue overload, n=1
rvalue overload, n=3
make_B
rvalue overload, n=4
lvalue overload, n=1
rvalue overload, n=5

Voir aussi

(C++11)
convertit l'argument en une xvalue
(modèle de fonction)
convertit l'argument en une xvalue si le constructeur de déplacement ne lève pas d'exception
(modèle de fonction)