Das Problem hierbei ist, dass wir im Konstruktor keinen Typabzug durchführen , da die Klasse als Vorlage verwendet wird . Wir haben immer eine R-Wert-Referenz. Das heißt, der Konstruktor für sieht tatsächlich so aus:TFoo(T&&)Foo
Foo(int&&)
Foo(2)funktioniert, weil 2es ein Wert ist.
Foo(x)nicht, weil xes sich um einen Wert handelt, an den nicht gebunden werden kann int&&. Sie können std::move(x)es auf den entsprechenden Typ umwandeln ( Demo )
Foo<int&>(x)funktioniert einwandfrei, da der Konstruktor Foo(int&)aufgrund von Regeln zum Reduzieren von Referenzen wird; anfangs ist es das, Foo((int&)&&)was Foo(int&)gemäß dem Standard zusammenbricht.
In Bezug auf Ihre "redundante" Abzugsanleitung: Zunächst gibt es eine Standardvorlage für den Abzug von Vorlagen für den Code, die sich im Grunde wie eine Hilfsfunktion verhält:
template<typename T>
struct Foo {
Foo(T&&) {}
};
template<typename T>
Foo<T> MakeFoo(std::add_rvalue_reference_t<T> value)
{
return Foo<T>(std::move(value));
}
//...
auto f = MakeFoo(x);
Dies liegt daran, dass der Standard vorschreibt, dass diese (fiktive) Vorlagenmethode dieselben Vorlagenparameter wie die Klasse (Just T) hat, gefolgt von Vorlagenparametern wie der Konstruktor (in diesem Fall keine; der Konstruktor ist nicht mit Vorlagen versehen). Dann sind die Typen der Funktionsparameter dieselben wie im Konstruktor. In unserem Fall Foo<int>sieht der Konstruktor nach der Instanziierung wie Foo(int&&)eine r-Wert-Referenz aus, mit anderen Worten. Daher die Verwendung von add_rvalue_reference_toben.
Offensichtlich funktioniert das nicht.
Wenn Sie Ihren "redundanten" Abzugsleitfaden hinzugefügt haben:
template<typename T>
Foo(T&&) -> Foo<T>;
Sie erlaubt der Compiler , dass zu unterscheiden, obwohl jede Art von Referenz an Tim Konstruktor ( int&, const int&oder int&&etc.), bestimmt der Typ für die Klasse abgeleitet ohne Bezug zu sein (nur T). Dies liegt daran , dass wir plötzlich sind Typinferenz durchführen.
Jetzt generieren wir eine weitere (fiktive) Hilfsfunktion, die folgendermaßen aussieht:
template<class U>
Foo<U> MakeFoo(U&& u)
{
return Foo<U>(std::forward<U>(u));
}
// ...
auto f = MakeFoo(x);
(Unsere Anrufe an den Konstruktor für die Zwecke der Klasse Template - Argument Abzug an die Helferfunktion umgeleitet, so Foo(x)wird MakeFoo(x)).
Dies ermöglicht es, einfach U&&zu werden int&und Tzu werdenint