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

SL & STL C++ Discussion :

Foncteurs pour algorithmes de stl


Sujet :

SL & STL C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre chevronné
    Inscrit en
    Novembre 2006
    Messages
    362
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 362
    Par défaut Foncteurs pour algorithmes de stl
    Salut,

    J'ai codé un certain nombre de foncteurs pour me faciliter la manipulation des conteneurs de mon appli.

    Je suis sur que ça existe déjà, mais je souhaite en refaire, ne serait-ce que pour apprendre et m'amuser.

    J'ai donc commençé par des choses comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class IsNull
    {
    public :
        template <typename BaseType> bool operator() (const BaseType* pT) {return pT == NULL;};
    };
    qui me permet de supprimer les pointeurs nulls dans un conteneur de pointeurs, avec un remove_if :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::remove_if(a.begin(),a.end(),IsNull());
    J'ai codé un foncteur Not, quelques foncteurs d'opérateurs ... et puis je me suis dit que tout ceci était peut-être un peu répétif, et que je devais pouvoir appeler n'importe quelle méthode des objets contenus dans mon conteneur, j'ai donc essayé de faire quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template <typename TFunctionType, TFunctionType funcRef>
    class ThisFunctionReturnsTrue
    {
    public :
        template <typename BaseType> bool operator() (const BaseType* pT) {return (pT->(*funcRef));};
    };
    L'idée était de s'en servir comme ça : par exemple pour compter le nombre d'objets bleus de mon conteneur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::count_if(a.begin(),a.end(),ThisFunctionReturnsTrue<void (A::*)(), A::isBlue);
    avec bien sur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    class A
    {
    ...
    public :
       bool isBlue();
    }
    Mais voilà, quand j'écris :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ThisFunctionReturnsTrue<void (A::*)(), A::isBlue)
    mon second paramètre est un pointeur (de fonction), et donc mon compilo me jette en me disant qu'il ne sait pas l'évaluer à la compilation.

    Y a-t-il un moyen de faire cela ?

    Merci d'avoir lu jusqu'ici
    Merci à ceux qui répondront

  2. #2
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Effectivement ce que tu cherches à faire existe déjà dans le standard ; tu peux au moins t'en inspirer si tu ne veux pas l'utiliser directement.

    Ton problème est que tu tentes de passer le pointeur de fonction en paramètre template (enfin quoique, avec une syntaxe correcte tu devrais pouvoir le faire) ; quoiqu'il en soit tu pourrais aussi le passer en paramètre au constructeur, ça te permettrait d'écrire une fonction qui simplifie la construction du foncteur (comme c'est justement systèmatiquement fait dans le standard).

    Par exemple :

    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
    template <typename TFunctionType>
    class ThisFunctionReturnsTrue_t
    {
    public :
     
        ThisFunctionReturnsTrue_t(TFunctionType F) F_(F) {}
     
        template <typename BaseType> bool operator() (const BaseType* pT) {return (pT->(*F_));};
     
    private :
     
        TFunctionType F_;
    };
     
    template <typename TFunctionType>
    ThisFunctionReturnsTrue_t<TFunctionType> ThisFunctionReturnsTrue(TFunctionType F)
    {
        return ThisFunctionReturnsTrue_t<TFunctionType>(F);
    }
     
    std::count_if(a.begin(), a.end(), ThisFunctionReturnsTrue(&A::isBlue));
    Note que tu peux faire des trucs plus génériques, avec des adapteurs de fonctions (ie. transformer une fonction membre en foncteur, binder des paramètres, ...).

  3. #3
    Membre chevronné
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Par défaut
    Qque remarques
    IsNull(): Pourquoi pas, mais c'est équivalent à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    bind2nd(equal_to<T>(), 0)
    (sans rentrer dans le débat de l'utilisation de NULL en C++)

    Pour compter les éléments bleus, je trouve la méthode un poil compliqué.
    Je préfère créer un prédicat à partir de la fonction membre. En reprenant ton exemple, ça donne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    struct Foo {
      bool isBlue() {...};
    };
    int main()
    {
      vector<Foo> v(10);
      std::count_if(v.begin(),v.end(), mem_fun_ref(&Foo::isBlue));
    }
    EDIT: Dsl pour le cross post

  4. #4
    Membre chevronné
    Inscrit en
    Novembre 2006
    Messages
    362
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 362
    Par défaut
    Salut,
    Merci de cette réponse !

    Citation Envoyé par Laurent Gomila
    tu pourrais aussi le passer en paramètre au constructeur
    Merci de cette proposition, c'est en effet plus simple.


    Citation Envoyé par Laurent Gomila
    Ton problème est que tu tentes de passer le pointeur de fonction en paramètre template (enfin quoique, avec une syntaxe correcte tu devrais pouvoir le faire)
    Puis-je te demander comment passer un pointeur en fonction de paramètre, puisque c'est possible ?

    Citation Envoyé par Jan Rendek
    Je préfère créer un prédicat à partir de la fonction membre. En reprenant ton exemple, ça donne:
    Oui, bien sur bien sur, il ne fait ausun doute que c'est plus efficace, mais l'objet de "l'exercice" était de pratiquer et d'apprendre.
    Je te remercie tout de même pour le conseil.

  5. #5
    Membre chevronné
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2006
    Messages
    366
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Mai 2006
    Messages : 366
    Par défaut
    Salut,

    Pour passer un pointeur de fonction comme argument template :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
     
    ReturnType function(Type1 parm1, Type2 parm2) {
    //...
    }
     
    template <ReturnType (*)(Type1, Type2)>
    class Functor {
    //...
    };
     
    //Pour l'instancier :
     
    Functor<&function> functor;
    Dans le cas d'un pointeur sur fonction memebre :

    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
     
     
    class A {
     
        public:
     
            ReturnType function(Type1 parm1, Type2 parm2) {
                //...
            }
    };
     
    template <ReturnType (A::*)(Type1, Type2)>
    class Functor {
    //...
    };
     
    //Pour l'instancier :
    Functor<&A::function> functor;
    Attention, contrairement aux pointeurs de fonction utilisés comme paramètres template, la conversion de pointeurs de fonction membre utilisés comme paramètre de template est interdite.

  6. #6
    Membre émérite Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Par défaut
    Question :

    Moi je n'utilise des foncteurs que quand j'ai besoin de créer des fonctions qui dépendent d'un contexte (closures).

    Mais quand ce sont de simples fonctions libres, quel avantage vous avez à les mettre sous forme de foncteurs, vu que les algorithmes de la STL acceptent les 2 sans distinction en général ?

  7. #7
    Membre chevronné
    Inscrit en
    Novembre 2006
    Messages
    362
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 362
    Par défaut
    Un première réponse :

    Imaginons que tu face un foncteur "Or" qui prend n autres foncteurs en paramètre et qui renvoie le "ou" des n ... et bien tu seras content d'avoir utilisé la même structure pour tous tes foncteurs.

  8. #8
    Membre émérite Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Par défaut
    J'ai pas compris.

    Tu veux dire qu'étant donné n foncteurs f1, f2, ... , fn tu veux créer la fonction

    OR(f1, f2, ... , fn) -> f1 || f2 || ... || fn

    ?

    (En fait j'ai menti tout à l'heure, j'utilise aussi souvent boost::function, donc je n'ai jamais de problème de compatibilité foncteur/fonctions.
    Mais par contre, faire des curryfications avec des fonctions à plus de 2 variables, me pose problème).

    Non mais sinon je ne vois pas le problème.
    Normalement, quand tu fais des fonctions qui acceptent des foncteurs, le type du foncteur est paramétrisé à l'aide des templates, donc ça peut être aussi bien un pointeur de fonction.

    EDIT : ouais en fait ça bug pour l'utilisation avec bind1st ou bind2nd. Mais heureusement on peut utiliser ptr_fun.

  9. #9
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Les appels à operator () des foncteurs peuvent être inlinés, contrairement aux pointeurs de fonctions pour lesquels il y a une indirection obligatoire. Ca peut avoir de l'importance par exemple dans un std::sort.

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

Discussions similaires

  1. Conseils pour algorithme ou programmation
    Par djahoo dans le forum Algorithmes et structures de données
    Réponses: 1
    Dernier message: 30/12/2007, 15h11
  2. Demande d'aide pour algorithme balistique
    Par aderdu91 dans le forum Algorithmes et structures de données
    Réponses: 3
    Dernier message: 12/04/2007, 13h59
  3. Aide pour algorithme
    Par Sinclaire dans le forum Langage
    Réponses: 5
    Dernier message: 29/03/2006, 19h58
  4. Besoin d'aide pour algorithme de traitement d'images
    Par Zenman94 dans le forum Algorithmes et structures de données
    Réponses: 13
    Dernier message: 07/04/2005, 14h31

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