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 :

Spécialisation de greater pour une classe template


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut Spécialisation de greater pour une classe template
    Hello,

    Je cherche à spécialiser std::greater pour un type std::pair.

    Je dois donc avoir 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
    namespace std
    {
    	template <>
    	struct greater<pair<TKey, TValue>> : binary_function<pair<TKey, TValue>, pair<TKey, TValue>, bool>
    	{
    		bool operator()(const pair<TKey, TValue>& x, const pair<TKey, TValue>& y)
    		{
                         return (x.second > y.second);
    		}
    	}
    }
    Mais bon, les arguments template sont eux-même des templates, ce que ne semble pas prévoir le template de base.

    Que faire ?

  2. #2
    Membre émérite

    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    533
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 533
    Par défaut
    La spécialisation partielle ne fonctionne pas ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    namespace std
    {
    	template <class TKey, class TValue>
    	struct greater<pair<TKey, TValue>> : binary_function<pair<TKey, TValue>, pair<TKey, TValue>, bool>
    	{
    		bool operator()(const pair<TKey, TValue>& x, const pair<TKey, TValue>& y)
    		{
                         return (x.second > y.second);
    		}
    	}
    }
    --

    Est-ce que, par ailleurs, il est bien conseillé de tripatouiller std::greater plutôt que de fournir des foncteurs là où il faut ?

  3. #3
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Il est vivement recommandé de n'écrire aucun code dans std::, à moins d'être un implémenteur de la lib standard.

    Mieux vaut utiliser un foncteur, en effet.

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    De manière générale, je ne suis pas très partisan d'aller "trifouiller" dans l'espace de noms std, surtout quand c'est pour définir un comportement "non conventionnel".

    Si je parle de "comportement non conventionnel", c'est parce que les algorithmes de comparaison d'une std::pair manipulent essentiellement pair.first et non pair.second.

    Tu m'objecteras sans doute que ce n'est pas bien grave parce que les algorithmes utilisent généralement lesser ou equal, mais c'est oublier un peu vite qu'il y a, en réalité, quatre paramètres template dans le cas d'une std::map:
    • Key : la clé à utiliser
    • T : la valeur
    • Compare qui vaut less<T> par défaut et
    • Allocator qui vaut allocaor<pair<const Key,T> > par défaut (bon, celui là ne nous intéresse pas ici )
    Mais cela signifie que tu peux parfaitement indiquer n'importe quel foncteur renvoyant un booléen à la place de Compare!!!

    Rien ne t'empêche donc d'envisager une d'avoir un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class MyClass 
    {
        /* ... */
        typedef std::pair<int,std::string> MyKey;
        private:
            std::map<MyKey, AType, std::greater<MyKey>> mymap;
    };
    Je soupçonnes d'ailleurs, que c'est à peu près ce que tu espères faire, non

    Le problème en allant trifouiller dans l'espace de noms std, c'est que, comme greater est un foncteur template, ton implémentation perso devra être définie... dans un fichier d'en-tête.

    Et c'est là que les problèmes commencent, surtout si tu définis greater pour "n'importe quel type de pair"

    En effet, le gros problème avec les fichiers d'en-tête, c'est que tu ne sais jamais jusqu'où il seront inclus : tu auras une vague idée des fichiers dans lesquels ils sont inclus de manière directe, mais, tu as le jeu des inclusions indirectes, et tu ne sais jamais où cela va s'arrêter au jeu d'un fichier qui inclut un fichier qui inclut un fichier qui inclut (la norme 2005 demande minimum 256 niveaux d'inclusions indirecte )... le fichier qui inclut ton fichier d'en-tête

    Tu pourrais donc te retrouver, bien malgré toi, avec des comportements assez surprenant si, "quelque part", tu venais à envisager d'avoir une autre map dont la clé est, elle aussi, une paire de valeur, et d'utiliser std::greater comme comparateur

    Ceci dit, si l'on regarde std::greater, il se suffit à lui même car son implémentation prend la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    template <class T> struct greater : binary_function <T,T,bool> {
      bool operator() (const T& x, const T& y) const
        {return x>y;}
    };
    "tout ce qu'il faut", c'est une structure qui fournisse l'opérateur ">"

    Et cette structure peut parfaitement être template, et prendre la forme de
    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
    template <typename Key, typename T>
    struct MyGreaterCompare
    {
        MyGreaterCompare(std::pair<Key, T> const & me):me(me){}
        friend
        bool operator >( MyGreaterCompare const & lhs,
                                 MyGreaterCompare const & rhs)
        {
            /* la logique qui va bien ;) */
            return lhs.me.first > rhs.me.first;
        }
        /* on peut maintenir une référence constante pour éviter les copies
         * inutiles ;) */
        std::pair<Key, T> const & me;
    };
    Et ta classe d'origine pourrait donc ressembler à quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class MyClass 
    {
        /* ... */
        typedef std::pair<int,std::string> MyKey;
        private:
            std::map< MyKey, AType,
                     std::greater<MyGreaterCompare<MyKey>>> mymap;
    };
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Vous avez raison : je vais finalement, selon vos bons conseils, utiliser un foncteur.

    Cela dit, merci koala01 d'expliquer comment malgré tout j'aurais pu utiliser greater<>. Ça apporte malgré tout de la connaissance !

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

Discussions similaires

  1. Spécialisation de membre d'une classe template
    Par Rewpparo dans le forum Langage
    Réponses: 17
    Dernier message: 10/04/2012, 11h13
  2. Réponses: 9
    Dernier message: 12/07/2010, 14h25
  3. Spécialisation de fonction template dans une class template
    Par summerstorm dans le forum Langage
    Réponses: 6
    Dernier message: 05/01/2010, 20h15
  4. Définition de méthodes pour une classe template
    Par Pragmateek dans le forum Langage
    Réponses: 13
    Dernier message: 20/12/2008, 00h46
  5. Réponses: 7
    Dernier message: 22/02/2007, 16h57

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