Le problème ici est que, puisque la classe est basée sur un modèle T
, dans le constructeur, Foo(T&&)
nous n'effectuons pas de déduction de type; Nous avons toujours une référence de valeur r. Autrement dit, le constructeur de Foo
ressemble en fait à ceci:
Foo(int&&)
Foo(2)
fonctionne parce que 2
c'est une valeur.
Foo(x)
ne le fait pas car il x
s'agit d'une valeur l qui ne peut pas être liée int&&
. Vous pouvez faire std::move(x)
pour le caster dans le type approprié ( démo )
Foo<int&>(x)
fonctionne très bien car le constructeur devient Foo(int&)
dû à des règles d'effondrement de référence; au départ, c'est ce Foo((int&)&&)
qui s'effondre Foo(int&)
selon la norme.
En ce qui concerne votre guide de déduction "redondant": Au départ, il existe un guide de déduction de modèle par défaut pour le code qui agit essentiellement comme une fonction d'aide comme ceci:
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);
Cela est dû au fait que la norme dicte que cette méthode de modèle (fictive) a les mêmes paramètres de modèle que la classe (Just T
), suivis de tout paramètre de modèle comme le constructeur (aucun dans ce cas; le constructeur n'est pas basé sur des modèles). Ensuite, les types des paramètres de fonction sont les mêmes que ceux du constructeur. Dans notre cas, après instanciation Foo<int>
, le constructeur ressemble à Foo(int&&)
une rvalue-reference en d'autres termes. D'où l'utilisation de ce qui add_rvalue_reference_t
précède.
Évidemment, cela ne fonctionne pas.
Lorsque vous avez ajouté votre guide de déduction «redondant»:
template<typename T>
Foo(T&&) -> Foo<T>;
Vous avez permis au compilateur de distinguer que, malgré toute référence attachée à T
dans le constructeur ( int&
, const int&
ou int&&
etc.), vous avez voulu le type déduit de la classe sans référence (juste T
). En effet , nous soudainement nous accomplissons l' inférence de type.
Maintenant, nous générons une autre fonction d'aide (fictive) qui ressemble à ceci:
template<class U>
Foo<U> MakeFoo(U&& u)
{
return Foo<U>(std::forward<U>(u));
}
// ...
auto f = MakeFoo(x);
(Nos appels au constructeur sont redirigés vers la fonction d'assistance aux fins de déduction des arguments du modèle de classe, Foo(x)
devient ainsi MakeFoo(x)
).
Cela permet U&&
de devenir int&
et T
de devenir simplementint