IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage C++ Discussion :

Classes templates : classes politiques, polymorphisme, spécialisation de méthodes templates avec des templates


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre à l'essai
    Profil pro
    Développeur informatique
    Inscrit en
    Juin 2003
    Messages
    14
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2003
    Messages : 14
    Points : 10
    Points
    10
    Par défaut Classes templates : classes politiques, polymorphisme, spécialisation de méthodes templates avec des templates
    Bonjour,
    Je souhaiterais modifier le comportement d'un code déjà écrit (celui des classes utilitaires de la bibliothèque d'imagerie NPP utilisant CUDA ). Mon problème est qu'il utilise des classes templates :
    • Image
    • ImagePacked héritant de Image (ImagePacked.h)
    • ImageCPU héritant de ImagePacked (ImagesCPU.h)
    • ImageNPP héritant de ImagePacked


    • AllocatorCPU utilisée dans ImagePacked (ImageAllocatorsCPU.h)
    • AllocatorNPP utilisée dans ImagePacked

    Les constructeurs et destructeur de imageCPU utilisent les méthodes de la classe (ici le terme structure serait surement plus approrié) AllocatorCPU par le biais de la classe ImagePacked pour allouer et désalouer les pixels des instances de imageCPU (de même avec *****NPP). Or, pour le cas d'imageCPU, je souhaiterais pouvoir choisir le type de mémoire allouée (non paginée ou paginée) en utilisant les fonctions adéquates (resp. malloc (ou new) et cudaMallocHost) puis les désalouer avec la bonne fonction (resp. free (ou delete) OU cudaFreeHost). Pour l'instant, c'est la mémoire non paginée qui est utilisée.
    L'idée serait donc d'introduire un paramètre extérieur définissant le type de mémoire à utiliser et de le conserver jusqu'à la désalocation.

    Comment puis-je faire sans trop modifier le code ?

    Merci d'avance pour toute réponse,
    Roll'Froy

    ImagePacked.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    namespace npp 
    {
      ...
     
      template<typename D, size_t N, class A>
      class ImagePacked: public npp::Image
      {
      public:
        ...
     
        ImagePacked(unsigned int nWidth, unsigned int nHeight): Image(nWidth, nHeight)
                                   , aPixels_(0)
                                   , nPitch_(0)
        {
          aPixels_ = A::Malloc2D(width(), height(), &nPitch_);
        }
     
        virtual
        ~ImagePacked()
        {
          A::Free2D(aPixels_);
        }
     
        ...
     
      private:
        D * aPixels_;
        unsigned int nPitch_;
      };
    } // npp namespace
    ImagesCPU.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    namespace npp
    {
     
      template<typename D, size_t N, class A>
      class ImageCPU: public npp::ImagePacked<D, N, A>
      {
        ...
      };
     
      typedef ImageCPU< Npp8u, 1, npp::AllocatorCPU<Npp8u,1> > ImageCPU_8u_C1;
      ...
    } // npp namespace
    ImageAllocatorsCPU.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    namespace npp
    {
      template <typename D, size_t N>
      class AllocatorCPU
      {
      public:
        static
        D *
        Malloc2D(unsigned int nWidth, unsigned int nHeight, unsigned int * pPitch)
        {
          NPP_ASSERT(nWidth * nHeight > 0);
     
          D * pResult = new D[nWidth * N * nHeight];
          *pPitch = nWidth * sizeof(D) * N;
     
          return pResult;
        };
     
        static
        void
        Free2D(D * pPixels)  
        {
          delete[] pPixels;
        };
      };
    } // npp namespace

  2. #2
    Membre à l'essai
    Profil pro
    Développeur informatique
    Inscrit en
    Juin 2003
    Messages
    14
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2003
    Messages : 14
    Points : 10
    Points
    10
    Par défaut Solution envisagée...
    La solution vers laquelle je me tourne pour l'instant est de rajouter un paramètre optionnel binaire aux constructeurs de ImageCPU. Ce paramètre (usePinnedMemory), qui a comme valeur par défaut False, est enregistré dans une variable d'instance. Cette variable servirait à modifier le comportement des constructeurs et destructeur de ImageCPU. Ceux-ci appellent les constructeurs et destructeur de la classe mère (ImagePacked).

    Je rencontre plusieurs difficultés :
    1. Déjà, comment "shunter" les constr. et destr. de la classe mère ? C'est à dire les appeler si usePinnedMemory = false et utiliser une partie de leur code quand usePinnedMemory = true ?
    2. N'est-ce pas possible de faire plus propre ? Car, avec ma méthode, je dois modifier une bonne partie de ImageCPU.h ...
    3. Les paramètres des templates sont
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      <typename D, size_t N, class A>
      et je fais une spécialisation : J'en fais qu'une mais ça demande à faire beaucoup de modifs pour rajouter qu'une seule fonctionnalité...


    N'hésitez pas à me demander plus d'infos, j'essaye d'être clair mais ces histoires de polymorphisme de classes templates ont du mal à passer ...

    Roll'Froy

    ImagesCPU.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    namespace npp
    {
      template<size_t N, class A>
      class ImageCPU<Npp8u, N, A> : public npp::ImagePacked<Npp8u, N, A>
      {
      public:
     
        ImageCPU()
        {
          this->usePinnedMemory_ = false;
        }
     
        ImageCPU(unsigned int nWidth, unsigned int nHeight, bool usePinnedMemory = false): ImagePacked<Npp8u, N, A>(nWidth, nHeight)
                                                                                         , usePinnedMemory_( usePinnedMemory )
        {
          this->aPixels_ = A::Malloc2D(this->width(), this->height(), &this->nPitch_, usePinnedMemory_);
        }
     
        ImageCPU(const npp::Image::Size & rSize, bool usePinnedMemory = false): ImagePacked<Npp8u, N, A>(rSize)
                                                                              , usePinnedMemory_( usePinnedMemory )
        {
          this->aPixels_ = A::Malloc2D(this->width(), this->height(), &this->nPitch_, usePinnedMemory_);
        }
     
        ImageCPU(const ImageCPU<Npp8u, N, A> & rImage, bool usePinnedMemory = false): Image(rImage)
                                                                                    , usePinnedMemory_( usePinnedMemory )
        {
          this->aPixels_ = A::Malloc2D(this->width(), this->height(), &this->nPitch_, usePinnedMemory_);
          A::Copy2D(this->aPixels_, this->nPitch_, rImage.pixels(), rImage.pitch(), this->width(), this->height());
        }
     
        ~ImageCPU()
        {
          A::Free2D(ImagePacked<Npp8u, N, A>::data(), usePinnedMemory_);
        }
     
      private:
        bool usePinnedMemory_;
      };
    } // npp namespace
    ImageAllocatorsCPU.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    namespace npp
    {
      template <typename D, size_t N>
      class AllocatorCPU
      {
      public:
     
        static
        D *
        Malloc2D(unsigned int nWidth, unsigned int nHeight, unsigned int * pPitch, bool usePinnedMemory = 0)
        {
          NPP_ASSERT(nWidth * nHeight > 0);
          D * pResult;
     
          if ( usePinnedMemory )
          {
            cudaError_t eResult;
            size_t mem_size = nWidth * N * nHeight * sizeof(D);
            eResult = cudaMallocHost( (void**) &pResult, mem_size );
            NPP_ASSERT(cudaSuccess == eResult);
          }
          else
            pResult = new D[nWidth * N * nHeight];
     
          *pPitch = nWidth * sizeof(D) * N;
     
          return pResult;
        };
     
        static
        void
        Free2D(D * pPixels, bool usePinnedMemory = 0)
        {
          if ( usePinnedMemory )
          {
            cudaError_t eResult;
            eResult = cudaFreeHost( pResult );
            NPP_ASSERT(cudaSuccess == eResult);
          }
          else
          {
            delete[] pPixels;
          }
        };
      };
    } // npp namespace

  3. #3
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Je ne suis pas sur d'avoir complètement compris ton problème. Pourquoi n'instancies-tu pas ta classe image avec un allocateur différent selon que le type d'allocation que tu souhaites ? As-tu jeter un coup d'oeil à ce tutoriel : Présentation des classes de Traits et de Politiques en C++ (et peut-être celui ci : Mariage de la Programmation Orientée Objet et de la Programmation Générique : Type Erasure) ?

  4. #4
    Membre à l'essai
    Profil pro
    Développeur informatique
    Inscrit en
    Juin 2003
    Messages
    14
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2003
    Messages : 14
    Points : 10
    Points
    10
    Par défaut
    Salut,
    Merci pour ta réponse. Hum, je pense que tu as compris mon problème : je souhaite implémenter une variante pour le type d'allocation dans la mémoire CPU. Donc, soit je modifie mon AllocatorCPU pour que je puisse choisir le type d'allocation que je veux (mémoire paginée/non paginée), soit je crée un "AllocatorCPUwithPN" (PN=PinnedMemory) et je choisis l'allocateur quand j'instancie ImagePacked (ce que tu me propose). Le problème, je pense, est que ces 2 méthodes demande pas mal de modifications amont (dans les classes ImageCPU ou/et ImagePacked).

    J'ai lu les articles que tu cites mais j'ai du mal à tout assimiler. J'ai compris la base des templates, cependant la marche suivante est un peu dure à franchir... Peut-être devrai-je me pencher sur un livre comme C++ Template Metaprogramming : Concepts, Tools, and Techniques from Boost and Beyond ?

    Bon, essayons ce que tu proposes :
    Déjà, les Allocator*** sont bien des classes de politique ?
    Puis-je utiliser les définitions des types ImageCPU*** dans ImageCPU.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef ImageCPU< Npp8u,  1, npp::AllocatorCPUwithPN<Npp8u, 1>  > ImageCPUwithPN_8u_C1;
    ou dois-je spécialiser ma classe template ImagePacked pour chaque Allocator***?

    Rien à voir avec les templates : peut-on appeler les constructeurs d'une classe mère (ou grand-mère) dans ceux (différents) de la classe fille ? Si c'est possible, comment gérer l'initialisation des variables d'instances de la classe mère (ou grand-mère) ?

    Roll'Froy

  5. #5
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    (rapidement)
    Citation Envoyé par k-djo Voir le message
    J'ai lu les articles que tu cites mais j'ai du mal à tout assimiler. J'ai compris la base des templates, cependant la marche suivante est un peu dure à franchir... Peut-être devrai-je me pencher sur un livre comme C++ Template Metaprogramming : Concepts, Tools, and Techniques from Boost and Beyond ?
    Il y a quelques livres de ref. sur la prog générique mais je ne suis pas le mieux placé pour te dire vers lequel aller de préférence.

    Citation Envoyé par k-djo Voir le message
    Bon, essayons ce que tu proposes :
    Déjà, les Allocator*** sont bien des classes de politique ?
    C'est ce qui y ressemble le +
    Citation Envoyé par k-djo Voir le message
    Puis-je utiliser les définitions des types ImageCPU*** dans ImageCPU.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef ImageCPU< Npp8u,  1, npp::AllocatorCPUwithPN<Npp8u, 1>  > ImageCPUwithPN_8u_C1;
    ou dois-je spécialiser ma classe template ImagePacked pour chaque Allocator***?
    L'idée est bien de ne pas modifier les classes ImagesTRUCMUCHE mais bien de spécialiser tes comportements dans les Allocator. Quelque chose du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    struct AllocatorCPU_P 
    {
       static void *allocate(size_t){...}
       static void free(void*){...}
    };
     
    struct AllocatorCPU_NP
    {
       static void *allocate(size_t){...}
       static void free(void*){...}
    };
    etc...
    template<...,class Allocator> class Image
    {
     
    /*...*/
       void foo()
       {
           /*....*/
          Allocator::allocate(/*...*/);
       }
    }
    typedef ImageCPUWithP Image<AllocatorCPU_P>;
    typedef ImageCPUWithNP Image<AllocatorCPU_NP>;
    Comme un typedef a besoin d'instancier tous les paramètres génériques (en attendant C++0x), tu auras certainement besoin de ça : Template rebinding en C++

    Citation Envoyé par k-djo Voir le message
    Rien à voir avec les templates : peut-on appeler les constructeurs d'une classe mère (ou grand-mère) dans ceux (différents) de la classe fille ? Si c'est possible, comment gérer l'initialisation des variables d'instances de la classe mère (ou grand-mère) ?
    Ca sent mauvais comme question Tu peux donner un exemple de ce que tu veux faire ?
    Tu peux appeler les constructeurs des classes mères (pas grand-mère) et des classes héritées virtuellement n'importe où dans l'arbre d'héritage, de préférence en suivant l'ordre adéquat :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    class A
    {};
    class B : public A
    {};
    class V
    {};
    class C : virtual public V
    {};
     
    class derivee : public B, public C
    {
       derivee()
       : V(), B(), C()
        //,  A() ->KO
       {}
    };
    Il ne faut pas hériter virtuellement pour pouvoir le faire (ne jamais tordre la syntaxe pour besoin de conception) ! C'est pour ça que je te demande ce que tu veux faire concrètement.

  6. #6
    Membre à l'essai
    Profil pro
    Développeur informatique
    Inscrit en
    Juin 2003
    Messages
    14
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2003
    Messages : 14
    Points : 10
    Points
    10
    Par défaut Polymorphisme de classes template OU spécialisation de méthode template de classe template (paramètres ≠ ) ?
    Bonjour,

    Tout d'abord, merci 3DArchi pour ta réponse, elle m'a bien servi (malgré qu'elle ait été apparemment écrite "rapidement" ) !
    Au départ je pensais juste modifier un peu le code d'AllocatorCPU mais, au final, c'est tout son comportement que je devais changer. Donc, comme tu me l'as conseillé, j'ai créé un AllocatorCPUwithPM possédant son propre comportement (en effet, pourquoi changer la conception ?!) et ça fonctionne...

    Maintenant, je cherche à généraliser mon code à un niveau supérieur. J'ai en effet une fonction function( Image(CPU/NPP), Image(CPU/NPP) ) que je surchargeais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void function( ImageCPU &, ImageCPU &);
    void function( ImageCPU &, ImageNPP &);
    void function( ImageNPP &, ImageCPU &);
    void function( ImageNPP &, ImageNPP &);
    ( ImageCPU et ImageNPP sont des classes template, j'ai volontairement omis les paramètres... )
    or le code était le même à part celui de méthodes de copie appartenant à des objets de type ImageNPP, ex :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
        | anotherImageNPP.copyFromHost( myImageCPU );
     ou |
        | anotherImageNPP.copyFromDevice( myImageNPP );
    et
        | anotherImageNPP.copyToHost( myImageCPU );
     ou |
        | anotherImageNPP.copyToDevice( myImageNPP );
    anotherImageNPP étant un objet interne à la fonction et myImage*** étant un des 2 paramètres de la fonction.
    Donc, déjà, j'ai surchargé ces méthodes, en supprimant "Host" ou "Device". Après, je vois deux solutions pour passer l'un des deux paramètres de ma fonction, qui peuvent être un objet de type soit ImageCPU soit ImageNPP, à mes méthodes copyFrom et copyTo :
    1. le polymorphisme en utilisant la classe mère ImagePacked;
    2. templater ces méthodes et les spécialiser.

    Le problème est que je ne vois pas comment implémenter ces solutions :
    1. Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
       
      void function( ImagePacked & myImage1, ImagePacked & myImage2)
      {
        ...
        anotherImageNPP.copyFrom( myImage1 );
        ...
        anotherImageNPP.copyTo( myImage2 );
      }
      Comment "caster" mes objets myImage# dans leur type (classe fille) d'origine alors que je ne le connais pas ?
    2. Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
       
      namespace
      {
        class ImageNPP
        {
              template <class I> void ImageNPP::copyFrom( I image) {}
        }
       template <ImageNPP> void ImageNPP::copyFrom( ImageNPP image) { ... }
       template <ImageCPU> void ImageNPP::copyFrom( ImageCPU image) { ... }
      }
      Je crois que ça pourrait fonctionner si je manipulais des classes classiques mais avec des classes templates ?

    le point difficile pour moi, c'est que les classes Image ( ImageCPU, ImageNPP et ImagePacked) sont templatées ( leurs paramètres : <typename D, size_t N, class A> ).

    Si les deux solutions sont possibles, laquelle est "la meilleure" ?

    Toujours en vous remerciant de me répondre ou de me lire,
    Roll'Froy

  7. #7
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Citation Envoyé par k-djo Voir le message
    Salut,
    Merci pour ta réponse. Hum, je pense que tu as compris mon problème : je souhaite implémenter une variante pour le type d'allocation dans la mémoire CPU. Donc, soit je modifie mon AllocatorCPU pour que je puisse choisir le type d'allocation que je veux (mémoire paginée/non paginée), soit je crée un "AllocatorCPUwithPN" (PN=PinnedMemory) et je choisis l'allocateur quand j'instancie ImagePacked (ce que tu me propose). Le problème, je pense, est que ces 2 méthodes demande pas mal de modifications amont (dans les classes ImageCPU ou/et ImagePacked).
    C'est le problème que permettent de résoudre les politiques (cf la 2ème partie de mon article). Tu paramétrises plusieurs parties indépendantes d'une classe en confiant l'implémentation à des types passés en paramètre à ton template. Tu peux ainsi externaliser l'implémentation pour l'allocation/désallocation de mémoire (une implémentation appellera delete, l'autre cudaFreeHost, par exemple).

    Si tu as des questions ou problèmes avec les templates, traits, politiques, la métaprogrammation ou autres, n'hésite pas on est là pour y répondre

  8. #8
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par Alp Voir le message
    C'est le problème que permettent de résoudre les politiques (cf la 2ème partie de mon article).
    C'est effectivement une des premières pistes que j'avais donné avec ton article en référence. Et d'après le dernier code, c'est une piste suivie

Discussions similaires

  1. Classe pour envoyer des mails avec des template
    Par RobertP dans le forum Langage
    Réponses: 1
    Dernier message: 24/12/2011, 10h49
  2. Question de liaison avec des template
    Par dj.motte dans le forum Langage
    Réponses: 18
    Dernier message: 26/09/2008, 17h42
  3. Réponses: 1
    Dernier message: 22/08/2007, 15h48
  4. Réponses: 6
    Dernier message: 29/11/2006, 11h56
  5. Créer un type matrice avec des templates
    Par souading3000 dans le forum C++
    Réponses: 2
    Dernier message: 15/06/2006, 11h24

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo