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 :

Déduction de type pour methode statique d'une classe template


Sujet :

Langage C++

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 17
    Points : 9
    Points
    9
    Par défaut Déduction de type pour methode statique d'une classe template
    Bonjour,

    J'ai besoin de définir des méthodes statiques templates qui utilisent le scope d'une classe template et dont les parametres sont déduis à la compilation. Illustration :
    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
     
    template <typename T>
    class type
    {
    public:
     
       template<typename U>
       static type<U> operation(const type<U>& x, const type<U>& y)
       {
          // par exemple
          return x.a*y.a;
       }
     
       T a;
    };
     
     
    // et un appel
    type<float> a = 5.0f;
    type<float> b = 4.0f;
    type<float> c = type::operation(a,b); // c = 20.0f
    // et non (comme le voudrais g++)
    type<float> c = type<float>::operation(a,b); // c = 20.0f
    // ou encore
    type<int> c = type<float>::operation(a,b); // c = 20.0f
    // etc ...
    Le scope est important, je ne veux pas définir ce type de methode a l'extérieur de la classe. Est ce que c'est réalisable ? Si oui comment ?

    Merci d'avance !

  2. #2
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Ce que tu souhaites faire est tout fait valide. La preuve en image :

    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
     
    #include <typeinfo>
     
    template <typename T>
    class type
    {
    public:
      type(const T& v) : a(v) { }
     
       template<typename U>
       static type<U> operation(const type<U>& x, const type<U>& y)
       {
          // par exemple
          return type<U>(x.a*y.a);
       }
     
       T a;
    };
     
    void test()
    {
      type<float> a(2.0f), b(3.0f);
     
      std::cout << "type<int> " << typeid(type<int>).name() << std::endl;
      std::cout << "type<???> " << typeid(type<int>::operation(a, b)).name() << std::endl;
    }
     
    int main()
    {
      test();
    }
    Compilé avec g++, on récupère :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    type<int> 4typeIiE
    type<???> 4typeIfE
    operation() a bien reconnu des type<float>, et a bien renvoyé un type<float> 4typeIfE au lieu de 4typeIiE pour un type<int>)
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 17
    Points : 9
    Points
    9
    Par défaut
    Non, j'ai du mal me faire comprendre.

    Je ne veux pas spécifier le type template quand j'appelle la méthode statique.
    Je veux
    type::operation(a,b)
    et non pas :
    type<T>::operation(a,b), pour T quelconque

    Si ma classe de base n'était pas une classe template, ca marcherai, le compilateur arrive à déduire le type avec les paramètres, mais dans mon cas il n'y arrive pas. Donc puis-je faire quelque chose pour y remédier ?

  4. #4
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Bonjour

    Tu peux toujours ajouter un paramètre par défaut pour ton template pour pouvoir l'appeler sans paramètre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    template <typename T = int>
    class type { ... };
     
    type<float> c = type<>::operation(a,b);
    Mais ça me semble pas être une bonne idée (tu crées une classe type<int> même si tu ne l'utilises pas)

    La méthode que j'aurais utilisé est une fonction non membre, soit en utilisant une fonction membre publique :
    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
    template <typename T = int>
    class type
    {  
        ...
        type<T>& operation(const type<T>& y)
        {
            a *= y.a;
            return *this;
        }
    };
     
    template<typename T>
    static type<T> operation(const type<T>& x, const type<T>& y)
    {
        type<T> x2(x);
        return x2.operation(y);
    }
    soit en utilisant une fonction en amie :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    template <typename T = int>
    class type
    {
        ...
        template<typename U>
        friend type<U> operation(const type<U>& x, const type<U>& y);
    };
     
    template<typename U>
    static type<U> operation(const type<U>& x, const type<U>& y)
    {
        return x.a * y.a;
    }

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 17
    Points : 9
    Points
    9
    Par défaut
    Si j'ajoute une valeur par défaut pour le paramètre template, cela ne marche pas (toujours la même erreur de compilation g++ au passage : template<class T> class A used without template parameters)

    Je suis d'accord, ca marche si j'utilise une fonction mais j'aimerai pouvoir acceder a la fonction via un operateur de scope (qui porte le nom de la classe template)...

  6. #6
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Ça marche chez moi (par contre, il faut quand même ajouter les fonctions de conversion U -> type<U>) (sous win7)

    Je suis d'accord, ca marche si j'utilise une fonction mais j'aimerai pouvoir acceder a la fonction via un operateur de scope (qui porte le nom de la classe template)...
    Le problème est que même si c'est une fonction statique, tu n'as pas 1 fonction pour toutes tes spécialisations mais bien 1 fonction par spécialisation (imagine si tu utilisais le type T dans ta fonction, tu aurais bien 1 fonction par spécialisation ; le fait de ne pas utiliser le type T ne doit rien changer pour le compilateur : il créer plusieurs fonctions statiques différentes, je pense).

    Les autres écritures que je t'ai proposé fonctionne.

    Si le problème est la portée de ta fonction, utilise un espace de nom

  7. #7
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 17
    Points : 9
    Points
    9
    Par défaut
    Citation Envoyé par gbdivers Voir le message
    Le problème est que même si c'est une fonction statique, tu n'as pas 1 fonction pour toutes tes spécialisations mais bien 1 fonction par spécialisation (imagine si tu utilisais le type T dans ta fonction, tu aurais bien 1 fonction par spécialisation ; le fait de ne pas utiliser le type T ne doit rien changer pour le compilateur : il créer plusieurs fonctions statiques différentes, je pense).
    Oui, mais au final le type template de la méthode statique est indépendant de celui de la classe. On pourrait faire cela sur une classe non "templatée", alors pourquoi pas sur un template ? Dommage ... ^^

    Citation Envoyé par gbdivers Voir le message
    Si le problème est la portée de ta fonction, utilise un espace de nom
    Je pense que je vais passer par la, utiliser un namespace du genre type_operations::, a voir si c'est pas trop lourd à l'utilisation.

    Merci en tout cas !

  8. #8
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par blitz_ Voir le message
    Oui, mais au final le type template de la méthode statique est indépendant de celui de la classe. On pourrait faire cela sur une classe non "templatée", alors pourquoi pas sur un template ? Dommage ... ^^
    Mais, comme précédemment expliqué par gbdivers, type<int> et type<float> sont deux types totalement différents (exactement comme si tu avais créé deux classes non template type1 et type2). Tu as donc deux fonctions membres de classes nommées operation() totalement distinctes. Et il faut bien fournir la classe à laquelle appartient la fonction (de la même manière qu'avec les classes non template tu aurais tu préciser laquelle utiliser).
    En fait le type template U des paramètres de la fonction est bien déduis, c'est le type template T de la classe à laquelle appartient operation() qui ne l'est pas et ne peux pas l'être.

    En fait ta comparaison avec la classe non template n'est pas bonne. La différence n'est pas d'avoir ou non un template, mais d'avoir une seule et unique classe ou plusieurs classes distinctes.

    Citation Envoyé par blitz_ Voir le message
    Je pense que je vais passer par la, utiliser un namespace du genre type_operations::, a voir si c'est pas trop lourd à l'utilisation.
    Avoir nom_classe::operation ou nom_namespace::operation ne me semble pas très différent au niveau lourdeur d'utilisation.

    par contre j'ai du mal à comprendre pourquoi tu cherches à designer ta classe de cette façon. Cela ne me semble pas de prime abord très sain.

  9. #9
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 17
    Points : 9
    Points
    9
    Par défaut
    Citation Envoyé par gl Voir le message
    par contre j'ai du mal à comprendre pourquoi tu cherches à designer ta classe de cette façon. Cela ne me semble pas de prime abord très sain.
    Je développe une librairie de math, et j'aurai voulu pouvoir accéder aux opérations disponibles du type, en utilisant son scope. Pourquoi ?

    Voila un type de base :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    template <typename T>
    class vec2
    {
    public:
        // Produit scalaire
        template <typename U>
        static U dot(const vec2<U>& x, const vec2<U>& y)
        {
            return x.x*y.x + x.y*y.y;
        }
     
        T x;
        T y;
    };
    Et voila comment j'aurai voulu m'en servir
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    // declaration (exemple entier short)
    vec2<int16> a(5, 6);
    vec2<int16> b(53, 16);
    // produit scalaire
    int16 dot_result = vec2::dot(a,b);
    Je trouve que le code est assez clair comme ca, pratique dans un code assez important.

  10. #10
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Le problème c'est justement que le type est vec2<16> pas vec2. Donc le scope est vec2<16>::

    Ce que tu cherches à faire se traduit généralement en C++ par une fonction non-membre, le tout (classes et fonctions) dans un namespace.

    Au passage, je ne vois pas de gain de clarté apporté par la précision d'une éventuelle classe à laquelle appartiendrait l'opération. Le type des paramètres est lié aux paramètres et le "module" auquel appartient la classe est fournie par l'espace de nom, pas par le nom d'une classe. Mais ça reste assez subjectif comme point de vue.
    Pour être plus précis, tu veux définir une fonction de classe non pas pour son rôle (elle n'a pas de raison conceptuelle d'être déclarée ainsi) mais pour un regrouper les éléments en un tout cohérent (ce qui est le but du namespace).

  11. #11
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par gl Voir le message
    Au passage, je ne vois pas de gain de clarté apporté par la précision d'une éventuelle classe à laquelle appartiendrait l'opération.
    Je plussoie. Je pense que c'est de cette manière qu'il faut procéder. Il y a une paire d'année, une discussion proposant la création d'une librairie de math "standard" pour le C++ a emergé sur la mailing list sweng-gamedev (je n'arrive pas à retrouver le thread en question, mais une recherche un peu poussée devrait te le permettre). Les fonctions libres (dot, cross, ...) étaient l'une des solutions proposées pour le design de cette librairie (en fait, c'était la solution qui a reçu le plus de support, par rapport à des fonctions membres où à des redéfinitions d'opérateurs).

    Et je rajoute le fait que dès que tu déclare une classe template, tu peux la spécialiser. Cette spécialisation, même si elle n'existe pas dans ta librairie, peut exister par ailleurs (être définie par exemple dans le code client de la librairie).

    Par conséquent, l'existence de type<float>::operation() n'entraine pas l'existence de type<int>::operation(). Du coup, on voit mal comment le compilateur pourrait permettre un accès à une fonction type::operation() dont l'existence n'est pas garantie.
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  12. #12
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par Emmanuel Deloget Voir le message
    Et je rajoute le fait que dès que tu déclare une classe template, tu peux la spécialiser. Cette spécialisation, même si elle n'existe pas dans ta librairie, peut exister par ailleurs (être définie par exemple dans le code client de la librairie).
    Et réciproquement, l'utilisation d'une fonction libre template permet de spécialiser cette fonction pour un type donnée indépendamment de la spécialisation de la classe.

  13. #13
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 17
    Points : 9
    Points
    9
    Par défaut
    Citation Envoyé par Emmanuel Deloget Voir le message
    Par conséquent, l'existence de type<float>::operation() n'entraine pas l'existence de type<int>::operation(). Du coup, on voit mal comment le compilateur pourrait permettre un accès à une fonction type::operation() dont l'existence n'est pas garantie.
    Oui, je pensais qu'étant donné que la fonction ne dépendait pas du type template, il y avait peut être un moyen de s'en sortir.

    Tout est clair pour moi, merci pour ces explications/clarifications

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 0
    Dernier message: 25/07/2007, 14h47
  2. Réponses: 7
    Dernier message: 22/02/2007, 16h57
  3. Réponses: 2
    Dernier message: 02/05/2006, 14h34
  4. Trouver le Type d'une classe template dynamiquement ?
    Par Serge Iovleff dans le forum Langage
    Réponses: 3
    Dernier message: 23/09/2005, 16h48
  5. changement de type pour un champ dans une table
    Par Missvan dans le forum PostgreSQL
    Réponses: 2
    Dernier message: 23/02/2004, 15h26

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