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:T
Foo(T&&)
Foo
Foo(int&&)
Foo(2)
funktioniert, weil 2
es ein Wert ist.
Foo(x)
nicht, weil x
es 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_t
oben.
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 T
im 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 T
zu werdenint