Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1384 connectés 

  FORUM HardWare.fr
  Programmation
  C++

  template - types spécifiques

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

template - types spécifiques

n°1990453
snafu8
Posté le 05-05-2010 à 13:54:40  profilanswer
 

Salut,
 
est-ce que c'est possible en c++, de déclarer un template, qui ne pourra être instancié que si le type présente certaines spécificités, par exemple un operateur *?

mood
Publicité
Posté le 05-05-2010 à 13:54:40  profilanswer
 

n°1990465
Un Program​meur
Posté le 05-05-2010 à 14:13:06  profilanswer
 

Il y a des moyens pour arriver a ce genre de chose.  Je conseille d'utiliser une bibliotheque qui les encapsule, p.e. boost concept check.


---------------
The truth is rarely pure and never simple (Oscar Wilde)
n°1990468
Joel F
Real men use unique_ptr
Posté le 05-05-2010 à 14:16:20  profilanswer
 

ou bien boost::enable_if ca depend si tu veux empecher l'instanciation OU prevenir d'une erreur.
J'avais uploadé un addeduml à boost type_traits avec des truc genre has_operator_xxx, qui peut servir.
Quand je rentre je te montre


Message édité par Joel F le 05-05-2010 à 14:17:10
n°1990503
Joel F
Real men use unique_ptr
Posté le 05-05-2010 à 16:29:05  profilanswer
 

Bon comme je me sens d'attaque, vla un truc fait sur le coin de la table.

 

Etape 1: detecter qu'un type T supporte operator*
En gros, on veut savoir si pour deux instances de T a et b, a*b est correcte.
L'idée est en gros d'essayer de caluler le type de retour de a*b, si on arrive * existe,
sinon non. Or, on veut pouvoir faire ça sans avoir d'erreur de compilation.

 

L'idée est d'alors d'utiliser le mécanisme de surcharge de fonction pour tomber dans un cas
foireux dans les moments ou * n'existe pas, et discriminer sur cet appel.

 

Le code:

 
Code :
  1. #include <iostream>
  2. #include <boost/mpl/bool.hpp>
  3. #include <boost/type_traits/remove_cv.hpp>
  4. using namespace std;
  5. namespace detail
  6. {
  7.     struct tag {};
  8.     struct any { template<class T> any(T const& ); };
  9.     tag operator*(any const&, any const& );
  10.                        char (& check(tag))[2];
  11.     template <class T> char check(T const& );
  12.     template<class T>
  13.     struct has_operator_multiplies_impl
  14.     {
  15.         static typename boost::remove_cv<T>::type& x;
  16.         static const bool value = sizeof( check((x * x)) ) == 1;
  17.     };
  18. }
  19. template <class T>
  20. struct has_operator_multiplies
  21. : boost::mpl::bool_<detail::has_operator_multiplies_impl<T>::value> {};
 

En gros, on cherche à calculer le sizeof de x*x. Soit x supporte cette operateur
et son type de retour tombe dans template <class T> char check(T const& )
soit non. Si il n'existe pas que ce passe-t-il ? et bien, c'est le * de any (qui est constructible
à partir de n'importe quoi) qui va etre selectionné. Il renvoit un tag qui va faire que l'on
va appeler char (& check(tag))[2];

 

Le sizeof de tout ça est donc : 1 si check renvoit char et 2 si il renvoit char[2].
On a donc discriminé la chose.

 

Exemple: http://codepad.org/ia244fNX

 

Etape 2: Utilisez ça dans une classe template
Maintenant qu'on sait que T a ou pas un operator*, il faut pouvoir utiliser cette information pour discriminer des classes.
On fait juste de la SFINAE avec enable_if.

 
Code :
  1. template<class T, class Enable = void>
  2. struct do_some_multiplication;
  3. template<class T>
  4. struct do_some_multiplication<T, typename boost::enable_if<has_operator_multiplies<T> >::type>
  5. {
  6.   void test(T const& a, T const& b )
  7.   {
  8.     cout << a*b << endl;
  9.   }
  10. };
 

Si le has_operator_multiplies<T> renvoit vrai pour T, la seconde specialsiation est prise. Sinon, c'ets la premiere.
Soit on ne mets rien pour obtenir une erreur du genre "incomplete type", soit on met sune static_assert.

 

Exemple: http://codepad.org/PIx3L7LS

 

Notes
les has_operator_xxx ont été plus ou  moins ajouter à Boost.typetraits mais je sais pas si c'ets dans la 1.43.
La stratégie à base de sizeof ce generalise avec une mini-macro, on peut aussi demander l'existence de methode avec une signature donnée ou l'existence de fonction avec un prototype donnée etc...


Message édité par Joel F le 05-05-2010 à 16:30:19
n°1991393
Amonchakai
Posté le 08-05-2010 à 08:28:39  profilanswer
 

Super, une fois de plus merci de poster ce genre de chose  :jap:  
 
Il y a juste un truc que je comprends pas trop:

Code :
  1. char (& check(tag))[2];


Ça c'est syntaxe pour la déclaration d'une fonction qui retourne un char[2] ?
 
 
Comme ca, c'est plus clair pour moi... (Je comprends bien qu'au final l'objectif est de retourner quelque chose de plus gros qu'un char si l'on tombe sur un "tag" )

Code :
  1. namespace detail
  2. {
  3.     struct tag {};
  4.     struct any { template<class T> any(T const& ); };
  5.     tag operator*(any const&, any const& );
  6.     int check(tag const& );
  7.     template <class T> char check(T const& );
  8.    
  9.     template<class T>
  10.     struct has_operator_multiplies_impl
  11.     {
  12.         static typename boost::remove_cv<T>::type& x;
  13.         static const bool value = sizeof( check((x * x)) ) == 1;
  14.     };
  15. }


Message édité par Amonchakai le 08-05-2010 à 08:33:50
n°1991430
Joel F
Real men use unique_ptr
Posté le 08-05-2010 à 14:01:59  profilanswer
 

int n'est pas garanti d'etre plus gros que char

n°1991431
Joel F
Real men use unique_ptr
Posté le 08-05-2010 à 14:02:46  profilanswer
 

ma semi-proposal de ce truc:

 

http://www.boostpro.com/vault/inde [...] directory=


Message édité par Joel F le 08-05-2010 à 14:02:54
n°1991453
Amonchakai
Posté le 08-05-2010 à 16:48:50  profilanswer
 

Hum ok, je vois...  
 
Je vais regarder de plus près boost::function_types. ca a l'air sympathoche ce que l'on peut faire avec.


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C++

  template - types spécifiques

 

Sujets relatifs
MySQL création de BDD : clés primaires/étrangères types ...template : utiliser un multimap
template et interface+héritage[C++] Spécialisation d'une fonction template un peu tordue...
Modification du template universatil joomlaTemplate de fichier de conf
Probleme(s) sur les TemplateClass Template + Friend
template aussiTemplate
Plus de sujets relatifs à : template - types spécifiques


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR