C ++ 11: Comment définir une fonction qui accepte une référence universelle d’un type d’object spécifique?

Problème: je développe un programme avec C ++ 11. Je veux écrire une fonction qui accepte les références rvalue et lvalue. (c.-à-d. référence universelle).

La fonction suivante accepte un paramètre de référence universel:

template void function(T&& t){/*SNIP*/} 

Cependant, il accepte tout type de paramètre. Cela ruine le type de sécurité de la fonction. Que dois-je faire si je veux qu’il accepte un type de paramètre spécifique?

Voici une solution à laquelle je peux penser:

 void function(Class& t){/*SNIP*/} void function(Class&& t){ function(t); } 

Cependant, c’est moche. Si je veux changer le paramètre à accepter ou changer le nom de la fonction, je dois mettre à jour les deux versions de la fonction. Y at-il un meilleur équivalent que cela?

EDIT: Problème résolu. Vous avez tous les deux très bien répondu. J’ai voté +1 aux deux réponses pour montrer mon appréciation. Je vais laisser cette question quelques jours. La réponse avec le plus de votes sera acceptée.

EDIT2: Je me retrouve avec le code suivant:

 template < class T, class=typename std::enable_if<std::is_same<Class, typename std::decay::type>::value>::type //Dummy template parameter > void function(T&&){} 

EDIT3: J’ai écrit une définition de macro à cette fin:

 #define uRefType(T, typeLimit) class T, class=typename std::enable_if<std::is_same<typename std::decay::type, typeLimit>::value>::type 

Exemple d’utilisation:

 template void function(T&&){} 

Une façon de faire est d’utiliser std::enable_if . C’est une structure fournie par l’en type_traits tête type_traits . Il est défini de manière à ce que enable_if::type soit du type B si la condition booléenne A évaluée à vrai lors de la compilation. Sinon c’est vide.

Par conséquent, si vous avez un modèle de fonction

 template  void fun(T &&) { /*...*/ } 

et si vous voulez vous assurer qu’il n’est défini que si T correspond à un certain type, vous pouvez utiliser la construction enable_if<...>::type place du type de retour (ici, void ). La condition booléenne A est alors définie comme quelque chose comme: T est int , et le type B est défini comme le type de retour d’origine de la fonction (ici, void ).

Donc, si nous voulons que l’ fun soit défini que si T est int , nous obtenons ceci:

 #include  template  typename std::enable_if::type>::value,void>::type fun(T &&) { } int main() { int lvali = 3; double lvald = 3.3; fun(3); fun(lvali); // fun(3.3); // this won't be accepted (not an int) // fun(lvald) // this won't be accepted (not an int) return 0; } 

Remarquez comment la condition booléenne est définie comme suit (en omettant std:: to pour une meilleure lisibilité):

 is_same::type>::value 

L’instruction decay est utilisée pour s’assurer que cela fonctionne indépendamment du fait que T soit int ou int & (et quelques autres cas spéciaux).


Remarques supplémentaires: Ce type d’astuce n’est vraiment utile que si la définition de la fonction en question est la même pour rvalue et pour lvalue. Dans de nombreux cas, ce ne sera pas le cas (parce que le cas rvalue implémentera un déplacement, la lvalue ne le fera pas ou quelque chose de similaire).

Une situation typique où les deux définitions sont en fait identiques est lorsque le corps de la fonction est très court et ne fait que transmettre le ou les arguments à un autre appel de fonction (éventuellement surchargé):

 template  void fun(T &&obj) { other_fun(std::forward(obj)); } 

Dans ce cas, il est probablement correct de ne pas utiliser enable_if ou une autre astuce, car la déclaration de other_fun garantira que seuls certains types seront acceptés.

Utilisez std::enable_if avec std::is_same :

 template::value>::type> void function(T&& t){/*SNIP*/} 

Et (comme indiqué pour la première fois dans la réponse de jogojapan, que j’ai oublié de mentionner), utilisez std::decay sur T , car T& n’est pas du même type qu’un T et const T n’est pas le même que T`:

 template< class T, class = typename std::enable_if< std::is_same::type>::value>::type> void function(T&& t){/*SNIP*/} 

Voir la démo sur http://ideone.com/ztkHsf .