Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

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

7 réponses
Avatar
Philippe MESMEUR
Bonjour =E0 tous,

Je voudrais savoir s'il est possible de d=E9clarer une classe template
dont l'argument serait une classe d=E9riv=E9e d'une classe donn=E9e.

Je m'explique, prenons la classe template suivante:

template <class T_Type>
class MyClass
{

private:
T_Type * m_ptr;

};


dans l'=E9tat actuel des choses, MyClass est utilisable avec n'importe
quel type de donn=E9

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 !=3D 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=E9thode "Process()".

l'id=E9al serait de pouvoir isol=E9e 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=E9clarer MyClass pour qu'elle ne
fonctionne qu'avec des parametre template d=E9rivant de MyBaseClass...
quelque chose comme:

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

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

private:
T_Type * m_ptr;

};

esp=E9rant avoir =E9t=E9 clair sur ma demande,
merci d'avance pour votre aide

Philippe

7 réponses

Avatar
ld
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.
Avatar
Sylvain SF
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.
Avatar
Fabien LE LEZ
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
Avatar
Falk Tannhäuser
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 <http://www.boost.org> cela fonctionne de façon similaire :

#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>
// ...
BOOST_STATIC_ASSERT((boost::is_base_of<T_Type, MyBaseClass>::value));

Voir aussi <http://www.boost.org/doc/libs/1_39_0/libs/type_traits/doc/html/boost_typetraits/reference/is_base_of.html> et
<http://www.boost.org/doc/libs/1_39_0/doc/html/boost_staticassert.html>.

Falk
Avatar
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&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;
Avatar
Michael Doubez
On 18 juin, 10:03, Yann Renard wrote:
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
Avatar
James Kanze
On Jun 18, 3:56 pm, Michael Doubez wrote:
On 18 juin, 10:03, Yann Renard wrote:
> 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