Namespaces
Variants

std:: forward

From cppreference.net
Utilities library
Definiert im Header <utility>
(1)
template < class T >
T && forward ( typename std:: remove_reference < T > :: type & t ) noexcept ;
(seit C++11)
(bis C++14)
template < class T >
constexpr T && forward ( std:: remove_reference_t < T > & t ) noexcept ;
(seit C++14)
(2)
template < class T >
T && forward ( typename std:: remove_reference < T > :: type && t ) noexcept ;
(seit C++11)
(bis C++14)
template < class T >
constexpr T && forward ( std:: remove_reference_t < T > && t ) noexcept ;
(seit C++14)
1) Leitet Lvalues entweder als Lvalues oder als Rvalues weiter, abhängig von T.

Wenn t eine Forwarding Reference (ein Funktionsargument, das als Rvalue-Referenz auf einen cv-unqualifizierten Funktions-Template-Parameter deklariert ist) ist, leitet diese Überladung das Argument an eine andere Funktion mit der Value Category weiter, die es beim Aufruf der Funktion hatte.

Beispielsweise, wenn in einem Wrapper wie dem folgenden verwendet, verhält sich das Template wie unten beschrieben:

template<class T>
void wrapper(T&& arg)
{
    // arg ist immer ein Lvalue
    foo(std::forward<T>(arg)); // Weiterleiten als Lvalue oder Rvalue, abhängig von T
}
  • Wenn ein Aufruf von wrapper() einen Rvalue std::string übergibt, dann wird T zu std::string abgeleitet (nicht std::string& , const std::string& , oder std::string&& ), und std::forward stellt sicher, dass eine Rvalue-Referenz an foo übergeben wird.
  • Wenn ein Aufruf von wrapper() einen const Lvalue std::string übergibt, dann wird T zu const std::string& abgeleitet, und std::forward stellt sicher, dass eine const Lvalue-Referenz an foo übergeben wird.
  • Wenn ein Aufruf von wrapper() einen nicht-konstanten Lvalue std::string übergibt, dann wird T zu std::string& abgeleitet, und std::forward stellt sicher, dass eine nicht-konstante Lvalue-Referenz an foo übergeben wird.
2) Leitet Rvalues als Rvalues weiter und verbietet die Weiterleitung von Rvalues als Lvalues.

Diese Überladung ermöglicht es, das Ergebnis eines Ausdrucks (wie z.B. eines Funktionsaufrufs), der ein Rvalue oder Lvalue sein kann, mit der ursprünglichen Wertkategorie eines Forwarding-Referenzarguments weiterzuleiten.

Beispielsweise, wenn ein Wrapper nicht einfach sein Argument weiterleitet, sondern eine Memberfunktion auf dem Argument aufruft und deren Ergebnis weiterleitet:

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

wobei der Typ von arg sein kann

struct Arg
{
    int i = 1;
    int  get() && { return i; } // Aufruf dieser Überladung ist Rvalue
    int& get() &  { return i; } // Aufruf dieser Überladung ist Lvalue
};

Der Versuch, einen Rvalue als Lvalue weiterzuleiten, beispielsweise durch Instanziierung der Form (2) mit Lvalue-Referenztyp T, ist ein Compilezeitfehler.

Inhaltsverzeichnis

Hinweise

Siehe Template-Argument-Deduktion für die speziellen Regeln hinter Forwarding-References ( T&& als Funktionsparameter verwendet) und Forwarding-References für weitere Details.

Parameter

t - das zu weiterleitende Objekt

Rückgabewert

static_cast < T && > ( t )

Komplexität

Konstante.

Beispiel

Dieses Beispiel demonstriert das perfekte Weiterleiten der Parameter an das Argument des Konstruktors der Klasse T . Zudem wird das perfekte Weiterleiten von Parameterpaketen gezeigt.

#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);
}

Ausgabe:

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

Siehe auch

(C++11)
wandelt das Argument in einen xvalue um
(Funktions-Template)
wandelt das Argument in einen xvalue um, wenn der Move-Konstruktor keine Ausnahme wirft
(Funktions-Template)