Template: forcer qu'un argument soit une dérivation d'une classe donnée

Le
Philippe MESMEUR
Bonjour à tous,

Je voudrais savoir s'il est possible de déclarer une classe template
dont l'argument serait une classe dérivée d'une classe donnée.

Je m'explique, prenons la classe template suivante:

template <class T_Type>
class MyClass
{

private:
T_Type * m_ptr;

};


dans l'état actuel des choses, MyClass est utilisable avec n'importe
quel type de donné

MyClass<int>
MyClass<float>
MyClass<std::string>
MyClass<???>

Maintenant, dans MyClass je rajoute une fonction "void Process()"
telle que ma classe devienne:

template <class T_Type>
class MyClass
{

public:
void Process()
{
if (m_ptr != 0)
{
m_ptr->Process();
}
}

private:
T_Type * m_ptr;

};

la classe MyClass<int> ne compilera plus?
la classe MyClass<FooBar> ne compilera que si la classe FooBar possede
une méthode "Process()".

l'idéal serait de pouvoir isolée dans une classe de plus haut niveau
toutes les fonction de T_Type qu'utilise MyClass (dans mon exemple il
n'y aurait que Process):

class MyBaseClass
{
void Process();
};

il faudrait maintenant pouvoir déclarer MyClass pour qu'elle ne
fonctionne qu'avec des parametre template dérivant de MyBaseClass
quelque chose comme:

template <class T_Type : MyBaseClass> /* ceci ne marche pas mais je
crois que ça illustre bien ce que je voudrais pouvoir faire */
class MyClass
{

public:
void Process()
{
if (m_ptr != 0)
{
m_ptr->Process();
}
}

private:
T_Type * m_ptr;

};

espérant avoir été clair sur ma demande,
merci d'avance pour votre aide

Philippe
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
ld
Le #19587771
On 17 juin, 18:21, Philippe MESMEUR wrote:
Bonjour à tous,

Je voudrais savoir s'il est possible de déclarer une classe template
dont l'argument serait une classe dérivée d'une classe donnée.

Je m'explique, prenons la classe template suivante:

template <class T_Type>
class MyClass
{

  private:
    T_Type * m_ptr;

};

dans l'état actuel des choses, MyClass est utilisable avec n'importe
quel type de donné

MyClass<int>
MyClass<float>
MyClass<std::string>
MyClass<???>

Maintenant, dans MyClass je rajoute une fonction "void Process()"
telle que ma classe devienne:

template <class T_Type>
class MyClass
{

  public:
    void Process()
    {
      if (m_ptr != 0)
      {
        m_ptr->Process();
      }
    }

  private:
    T_Type * m_ptr;

};

la classe MyClass<int> ne compilera plus?
la classe MyClass<FooBar> ne compilera que si la classe FooBar possede
une méthode "Process()".

l'idéal serait de pouvoir isolée dans une classe de plus haut niveau
toutes les fonction de T_Type qu'utilise MyClass (dans mon exemple il
n'y aurait que Process):

class MyBaseClass
{
  void Process();

};

il faudrait maintenant pouvoir déclarer MyClass pour qu'elle ne
fonctionne qu'avec des parametre template dérivant de MyBaseClass...
quelque chose comme:

template <class T_Type : MyBaseClass> /* ceci ne marche pas mais je
crois que ça illustre bien ce que je voudrais pouvoir faire */
class MyClass
{

  public:
    void Process()
    {
      if (m_ptr != 0)
      {
        m_ptr->Process();
      }
    }

  private:
    T_Type * m_ptr;

};

espérant avoir été clair sur ma demande,
merci d'avance pour votre aide



Je pense que ce que tu veux est decrit dans

http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

qui est fait pour ca (si j'ai bien compris ta demande).

a+, ld.
Sylvain SF
Le #19590581
Philippe MESMEUR a écrit :

Je voudrais savoir s'il est possible de déclarer une classe template
dont l'argument serait une classe dérivée d'une classe donnée.



class MyClass<? : /*extends*/ MyBaseClass> {
}

ça marche en Java mais pas en C++ (pour lequel les génériques
tiennent du "fancy macro processor" - comme ils disent).

je ne connais pas de solution (élégante) mais si elle existait
cela me serait fort agréable.

Sylvain.
Fabien LE LEZ
Le #19590721
On Wed, 17 Jun 2009 09:21:59 -0700 (PDT), Philippe MESMEUR

il faudrait maintenant pouvoir déclarer MyClass pour qu'elle ne
fonctionne qu'avec des parametre template dérivant de MyBaseClass...



M'est avis que Loki contient quelque chose comme ça.

Par exemple :

template <class T_Type>
class MyClass
{
STATIC_CHECK (SUPERSUBCLASS (T_Type, MyBaseClass))
...

STATIC_CHECK et SUPERSUBCLASS sont définis pages 23 et 34
(respectivement) de "Modern C++ Design" (Alexandrescu) :
http://books.google.com/books?id=aJ1av7UFBPwC&printsec=frontcover&source=gbs_navlinks_s

Ou bien, tu peux directement télécharger le code :
http://loki-lib.sourceforge.net/index.php?n=Main.Download
Falk Tannhäuser
Le #19591131
Fabien LE LEZ schrieb:
On Wed, 17 Jun 2009 09:21:59 -0700 (PDT), Philippe MESMEUR

il faudrait maintenant pouvoir déclarer MyClass pour qu'elle ne
fonctionne qu'avec des paramètre template dérivant de MyBaseClass...



M'est avis que Loki contient quelque chose comme ça.

Par exemple :

template <class T_Type>
class MyClass
{
STATIC_CHECK (SUPERSUBCLASS (T_Type, MyBaseClass))
...



Avec Boost
#include #include // ...
BOOST_STATIC_ASSERT((boost::is_base_of<T_Type, MyBaseClass>::value));

Voir aussi
Falk
Yann Renard
Le #19591731
Fabien LE LEZ wrote:
On Wed, 17 Jun 2009 09:21:59 -0700 (PDT), Philippe MESMEUR

il faudrait maintenant pouvoir déclarer MyClass pour qu'elle ne
fonctionne qu'avec des parametre template dérivant de MyBaseClass...



M'est avis que Loki contient quelque chose comme ça.

Par exemple :

template <class T_Type>
class MyClass
{
STATIC_CHECK (SUPERSUBCLASS (T_Type, MyBaseClass))
...

STATIC_CHECK et SUPERSUBCLASS sont définis pages 23 et 34
(respectivement) de "Modern C++ Design" (Alexandrescu) :
http://books.google.com/books?id=aJ1av7UFBPwC&printsec=frontcover&source=gbs_navlinks_s

Ou bien, tu peux directement télécharger le code :
http://loki-lib.sourceforge.net/index.php?n=Main.Download



Et pourquoi pas quelque chose comme ça ?

template <class T_Type>
class MyClass
{
MyBaseClass* m_pBase;
...

et quelque part :

m_pBase=&un_T_Type;
Michael Doubez
Le #19593921
On 18 juin, 10:03, Yann Renard
Fabien LE LEZ wrote:
> On Wed, 17 Jun 2009 09:21:59 -0700 (PDT), Philippe MESMEUR
>
>> il faudrait maintenant pouvoir déclarer MyClass pour qu'elle ne
>> fonctionne qu'avec des parametre template dérivant de MyBaseClass...

> M'est avis que Loki contient quelque chose comme ça.

> Par exemple :

> template <class T_Type>
> class MyClass
> {
>    STATIC_CHECK (SUPERSUBCLASS (T_Type, MyBaseClass))
>    ...

> STATIC_CHECK et SUPERSUBCLASS sont définis pages 23 et 34
> (respectivement) de "Modern C++ Design" (Alexandrescu) :
>http://books.google.com/books?id=aJ1av7UFBPwC&printsec=frontcover&so u...

> Ou bien, tu peux directement télécharger le code :
>http://loki-lib.sourceforge.net/index.php?n=Main.Download

Et pourquoi pas quelque chose comme ça ?

template <class T_Type>
class MyClass
{
   MyBaseClass* m_pBase;
   ...

et quelque part :

   m_pBase=&un_T_Type;



Parcece que c'est plus ou moins ce que font Loki et Boost (ils
essayent de matcher un paramètre de fonction) mais que le message
d'erreur est bien moins parlant.

--
Michael
James Kanze
Le #19598001
On Jun 18, 3:56 pm, Michael Doubez
On 18 juin, 10:03, Yann Renard > Fabien LE LEZ wrote:
> > On Wed, 17 Jun 2009 09:21:59 -0700 (PDT), Philippe MESMEUR
> >


> >> il faudrait maintenant pouvoir déclarer MyClass pour
> >> qu'elle ne fonctionne qu'avec des parametre template
> >> dérivant de MyBaseClass...



> > M'est avis que Loki contient quelque chose comme ça.



> > Par exemple :



> > template <class T_Type>
> > class MyClass
> > {
> > STATIC_CHECK (SUPERSUBCLASS (T_Type, MyBaseClass))
> > ...



> > STATIC_CHECK et SUPERSUBCLASS sont définis pages 23 et 34
> > (respectivement) de "Modern C++ Design" (Alexandrescu) :
> >http://books.google.com/books?id=aJ1av7UFBPwC&printsec=frontcover& sou...



> > Ou bien, tu peux directement télécharger le code :
> >http://loki-lib.sourceforge.net/index.php?n=Main.Download



> Et pourquoi pas quelque chose comme ça ?



> template <class T_Type>
> class MyClass
> {
> MyBaseClass* m_pBase;
> ...



> et quelque part :

> m_pBase=&un_T_Type;



Parce ce que c'est plus ou moins ce que font Loki et Boost
(ils essayent de matcher un paramètre de fonction) mais que le
message d'erreur est bien moins parlant.



En revanche, c'est bien moins lourd que Loki ou Boost, et avec
un bon choix de nom de variable (genre
ensure_that_T_derives_from_MyBaseClass), le message peut être
clair, même s'il n'est pas forcement dans un anglais correct.

Le vrai problème (qu'on peut espérer résoulu dans Boost), c'est
d'assurer que le test se fait dans tous les cas où le template
est instantié. Mettre l'affectation dans une fonction
quelconque, ça n'apporte rien si la fonction n'est pas
instantiée. Et éventuellement aussi, de faire en sort que le
test n'ajoute rien à la taille de la classe, ni au code
réelement généré.

J'avoue aussi que j'utiliserais plutôt la résolution du
surcharge pour discriminer. Quelque chose du genre :

D'une bibliothèque plus générale :
typedef char TrueType ;
struct FalseType { char a[2] ; } ;

template< typename T >
class MyClass
{
static TrueType discriminator( MyBaseClass* ) ;
static FalseType discriminator( ... ) ;

static void testForDerivation()
{
char cestIciQuOnMetLeMessageDErreur[
sizeof( discriminator( (T*)( 0 ) ) == TrueType ] ;
}

MyClass()
{
&MyClass::testForDerivation ;
}
} ;

, en prenant l'adresse de testForDerivation dans tous les
constructeurs. (Prendre l'adresse d'une fonction provoque sont
instantiation.) Mais évidemment, c'est déjà nettement plus lourd
que ce qui a été proposé, et puisque c'est déjà implémenté en
Boost...

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Publicité
Poster une réponse
Anonyme