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

C++ Discussion :

template de classe template


Sujet :

C++

  1. #1
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut template de classe template
    Bonjour à tous.
    J'ai un doute si ce que je veux faire est possible.
    Mon problème est que si on a :

    template<typename T>
    class Truc;

    Alors, Truc n'est pas considéré comme un type.

    Voici mon objectif :

    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
    template<typename T>
    struct NbTemplate
    {
        static const int value=0;
    };
     
    template<template<class>class T>
    struct NbTemplate<T>
    {
        static const int value=1;
    };
     
    template<template<class,class>class T>
    struct NbTemplate<T>
    {
        static const int value=2;
    };
    //...
    Ou, plus généralement, en c++0x :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template<template<typename ...Args>class T>
    struct NbTemplate<T>
    {
        static const int value=sizeof...(Args);
    };
    Malheureusement, ce code ne compile pas car T n'est pas un type (ce qui fait qu'il n'y a aucune utilité à la classe NbTemplate et ce qui l'empêche de compiler).

    L'objectif final était d'écrire une matrice de taille connue à la compilation et qui pouvait donc prendre 2 types d'allocateurs (1 avec juste T, l'autre avec T et le nombre d'octets à allouer) sans dupliquer le code :

    J'aurais fait :

    template<typename T, unsigned Width, unsigned Height, class Allocator>
    class Matrix;

    et dedans, j'aurais fait un branchement si Allocator prend un ou deux template.

    Si vous connaissez une solution.

    Merci.

  2. #2
    Membre éclairé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    426
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 426
    Points : 827
    Points
    827
    Par défaut
    Salut,
    Ne peux-tu pas tout simplement faire un patron de class avec deux constructeurs, le premier avec un seul argument T et l'autre avec T et le nombre d'octets à allouer?

  3. #3
    Membre confirmé
    Avatar de gb_68
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2006
    Messages
    232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2006
    Messages : 232
    Points : 545
    Points
    545
    Par défaut
    Bonjour,
    Citation Envoyé par NoIdea Voir le message
    template<typename T>
    class Truc;

    Alors, Truc n'est pas considéré comme un type.
    Mais Truc<Machin> sera un type.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template<typename T, unsigned Width, unsigned Height, class Allocator>
    class Matrix;
    Allocator est déclaré comme type (et non template<typename T, unsigned Width, unsigned Height, template<typename> class Allocator> class Matrix; ).
    Il est possible dans ce cas détecter le nombre de paramètres templates de Allocator comme cela :
    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
    template<typename T>
    struct NbTemplate
    {
        static const int value=0;
    };
     
    template<template<class>class T, typename Arg1>
    struct NbTemplate< T<Arg1> >
    {
        static const int value=1;
    };
     
    template<template<class,class>class T, typename Arg1, typename Arg2>
    struct NbTemplate< T<Arg1,Arg2> >
    {
        static const int value=2;
    };
     
    template<template<class,size_t>class T, typename Arg1, size_t Size>
    struct NbTemplate< T<Arg1,Size> >
    { 
        // ? static const int value=2;
    };

  4. #4
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Ce n'est pas spécialement parce que ce n'est pas un type, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    template<class> class A;
    template<template<class> class> class B;
    template<> class B<A> {};
    Ne pose aucun problème.

    Le problème c'est que tu déclares une classe template pour un type et que tu la spécialises pour autre chose que des types, c'est comme si tu avais fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    template<class> class A;
    template<> class A<0> {};
    Code dont le fait qu'il ne compile pas ne surprendra pas grand monde ...

    Le dernier code que tu postes (en C++1x) ne marche pas pour une autre raison, ca ne sert à rien de nommer les paramètres template des TTP, ils sont inutilisable, en particulier ton Arg...

    Et enfin, même en supposant que ca puisse compiler, il y aurait un problème (en C++1x pour ce point). Imagines que tu es le compilo et que tu vois ca :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    template<class...> struct B;
     
    template<class T> struct B<T> {};
    template<class T, class U> struct B<T,U> {};
     
    //Puis avec ton code
    NbParam<B>::value;
    Comment tu détermines le nombre !? 1 ou 2 ?

    Sinon, voila la solution de gb_68 en C++1x (pour des paramètre templates du TTP qui ne sont que des types (*) ) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    template<class> struct NbParam;
     
    template<template<class...>class T, class... Arg>
    struct NbParam<T<Arg...> >
    { enum { value = sizeof...(Arg) }; };
    (*) Ce point peut paraitre restrictif mais ne l'est pas, car il est facile (et courrant) de transformer les constantes entières en type pour ne gérer que des types, mpl propose des outils pour ca, et il y en a aussi en C++1x.

  5. #5
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Ne peux-tu pas tout simplement faire un patron de class avec deux constructeurs, le premier avec un seul argument T et l'autre avec T et le nombre d'octets à allouer?
    Merci, c'est parfait en fait : puisque la taille de la matrice est connue à la compilation, je n'ai besoin d'allouer de la mémoire qu'à la création. Problème résolut. Merci.

    Cependant, pour mes projets futurs, voici une nouvelle question :

    Soit une classe A template pouvant prendre deux types d'allocateurs :
    -un allocateur<T>
    -un allocateur<T,B>
    La classe A hérite de allocateur<...>

    Comment écrire la classe A de telle façon que l'utilisateur ne passe que allocateur et non allocateur<...> en template ?
    Est-il possible d'éviter de l'écrire en double ?

  6. #6
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Je ne comprends pas trop ta question. Il suffit de faire un TTP (Template Template Paramter) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    template<template<class...> class> struct A;
    template<template<class,class> class Allocator>
    struct A<Allocator> : Allocator<?,?> {};
    template<template<class> class Allocator>
    struct A<Allocator> : Allocator<?> {};
    Après pour remplacer les ?, soit tu passes un autre paramètre template que tu inséreras à la bonne place, on gagne pas grand chose si ce n'est d'éviter la répétition de se paramètre si il y a plusieurs TTP.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    template<class T, template<class,class> class Allocator>
    struct A<Allocator> : Allocator<T,T> {};
    Sinon tu décide toi même du paramètre, mais ca sera toujours le même.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    template<class T, template<class,class> class Allocator>
    struct A<Allocator> : Allocator<int,int> {};
    Soit tu peux utiliser une classes de traits pour choisir un autre type qui dépendra soit d'un autre paramètre template soit du TTP lui-même.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    template<template<class...> class> struct TTP_Trait
    { typedef int Type; };
     
    template<template<class...> class> struct A;
    template<template<class,class> class Allocator>
    struct A<Allocator> : Allocator<typename TTP_Trait<Allocator>::Type,typename TTP_Trait<Allocator>::Type> {};
    Si par "écrire en double" tu veux dire devoir écrire les deux spécialisations, alors oui c'est possible dans certains cas : ceux où tu peux déterminer les paramètre à passer, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    template<template<class...> class Allocator, class... Arg>
    struct A : Allocator<Arg...> {};

  7. #7
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    J'avais abandonné cette partie du projet un peu, pensant que c'était réglé. Cependant, je n'arrive toujours pas à trouver la solution :



    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
     
    template<typename T, unsigned L, unsigned C, bool Static, template<class> class Allocator>
    class Matrix<T,L,C,Static, Allocator> : public Allocator<T>
    {
     
    };
     
     
    template<typename T, unsigned L, unsigned C, bool Static, template<class, unsigned N> class Allocator>
    class Matrix<T,L,C,Static, Allocator> : public Allocator<T,L*C>
    {
     
    };
     
    template<typename T, unsigned Nb>
    struct MyAlloc
    {
     
    };
     
     
    using namespace std;
     
    int main()
    {
        Matrix<float, 3,3,true,MyAlloc> m;
        Matrix<float, 3,3,true,std::allocator> m;
     
        return 0;
    }
    J'ai enlevé le
    template<typename T, unsigned L, unsigned C, bool Static, template<class...> class>
    class Matrix;

    car unsigned n'est pas une classe.

    Ma question : est-il possible de faire pour que le code ci-dessus compile ?

  8. #8
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    (pour des paramètre templates du TTP qui ne sont que des types (*) )

    (*) Ce point peut paraitre restrictif mais ne l'est pas, car il est facile (et courrant) de transformer les constantes entières en type pour ne gérer que des types, mpl propose des outils pour ca, et il y en a aussi en C++1x.
    Si tu enlève la déclaration du template ca ne marchera jamais. Il y a une grosse condition sur les templates, c'est que les listes des paramètres template des spécialisations doit matcher la liste des paramètres de la déclaration. Or c'est pas le cas car template<class, size> ne match pas template<class...>

    Si tu passes par des std::integral_constant, ca va marcher, par contre ca devient verbeux en première approche :

    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
     
     
    template<class T, template<class...> class Allocator, class...>
    class Matrix : public Allocator<T> {};
     
    template<typename T, template<class,class> class Allocator, size_t L, size_t C>
    class Matrix<T,Allocator,std::integral_constant<size_t,L>,std::integral_constant<size_t,C> >
      : public Allocator<T,std::integral_constant<size_t,L*C> >
    { };
     
    template<typename, class>
    struct MyAlloc;
     
    template<typename T, size_t N>
    struct MyAlloc<T,std::integral_constant<size_t,N> >
    { };
     
    int main()
    { 
      Matrix<float,MyAlloc,std::integral_constant<size_t,3>,std::integral_constant<size_t,3> > m1;
      Matrix<float,std::allocator,std::integral_constant<size_t,3>,std::integral_constant<size_t,3> > m2;  
     
      system("PAUSE");
      return EXIT_SUCCESS;
    }
    (Ca devient un peu moins verbeux en passant par une classe intermédiaire qui transforme les entier en type de manière invisible, un peu dans l'idée de WrapAlloc si dessous mais pour Matrix en entier.

    Sinon tu peux tranformer ton allocateur qui prend des entiers en paramètre qui ne prend qu'une classe en fixant avant les paramètre entier :

    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
     
    template<class T, template<class...> class Allocator, class...>
    class Matrix : public Allocator<T> {};
     
    template<template<class,size_t> class Alloc, size_t L, size_t C>
    struct WrappAlloc
    {
      template<class T>
      struct Result : Alloc<T,L*C> {};
    };
     
    template<typename, size_t>
    struct MyAlloc {};
     
    int main()
    { 
      Matrix<float,WrappAlloc<MyAlloc,3,3>::Result > m1;
      Matrix<float,std::allocator> m2;  
     
      system("PAUSE");
      return EXIT_SUCCESS;
    }

  9. #9
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Merci de m'avoir confirmer qu'il fallait changer le unsigned en type (ce qui est très énervant syntaxiquement).
    Une solution sans c++1x existe ?

  10. #10
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Sans variadic et sans integral_constant ?

    integral_constant ca se remplace facilement, tu as même le code exact dans le draft :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    //adapté sans C++1x
    template<class T, T v>
    struct integral_constant {
      static const T value = v;
      typedef T value_type;
      typedef integral_constant<T,v> type;
      operator value_type() { return value; }
    };
    Les variadics, ca se remplace par des TypeList. Regardes du coté de MPL ou Loki pour voir comment les faire (il n'y a rien de très compliqué dés que tu as bien assimilé le fait de penser fonctionnel).

Discussions similaires

  1. Syntaxe fonction template dans classe template
    Par Aleph69 dans le forum C++
    Réponses: 6
    Dernier message: 15/07/2011, 16h32
  2. Réponses: 4
    Dernier message: 15/10/2008, 10h33
  3. template dans un template de classe
    Par Bob.Killer dans le forum Langage
    Réponses: 1
    Dernier message: 18/12/2007, 16h44
  4. [Template] Problème Classe Template
    Par gimpycpu dans le forum Langage
    Réponses: 7
    Dernier message: 23/05/2007, 06h10
  5. Réponses: 15
    Dernier message: 21/08/2006, 02h41

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