Ihre Verwechslung beruht wahrscheinlich auf Ihrer Annahme, dass in beiden Fällen T
int
ist. Aus diesem Grund vermuten Sie, dass diese beiden Fälle ähnlich sind. In Wirklichkeit sind sie nicht. In der Klassenversion geben Sie manuell an, was T
ist. Sie sagen dem Compiler explizit, dass T
int
ist. Der Konstruktorparametertyp T &&
wird in diesem Fall int &&
, der nicht an einen regulären Lvalue gebunden werden kann. Daher der Fehler.
In der Funktionsversion sagen Sie dem Compiler nicht, was T
ist, aber stattdessen erwarten Sie, dass der Compiler daraus abgeleitet. In Situationen wie Ihrer ist die Sprache absichtlich darauf ausgelegt, T
als int &
abzuleiten (Hinweis: nicht als int
, sondern eher als int &
). Sobald T
als int &
abgeleitet wird, führen die so genannten "reference collapsing" rules zu Funktionsparameter Typ werden int &
- eine gewöhnliche lvalue Verweis. Dieser Parameter kann erfolgreich an das Lvalue-Argument i
gebunden werden.
Das erklärt den Unterschied, den Sie beobachten.
Aus Gründen der Versuch, im letzteren Fall können Sie Template-Argument Abzug unterdrücken und die Template-Argument explizit angeben
succeed<int>(i);
Das gewaltsam T
als int
geben wird und wie in der zum gleichen Fehler führen Klassenversion aus dem gleichen Grund.
Ebenso können Sie „simulieren“ Verhalten der Funktion für die Klasse durch das Template-Argument als int &
Angabe
test<int &> t(i);
die gleiche „Referenz kollabiert“ Regeln Konstruktor Aufruf erfolgreich zu kompilieren machen.
Es wäre einfacher zu erklären, wenn wir tatsächlich die Fehler kennen, die Sie bekommen. Wenn Sie Fragen zu Buildfehlern stellen, sollten Sie immer die vollständige Fehlerausgabe in den Hauptteil der Frage einfügen. Bitte bearbeiten Sie Ihre Frage, um diese zu berücksichtigen. Bitte geben Sie auch den verwendeten Compiler an und welche Version davon. –