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 :

Template de pointeur sur fonction (presque) générique


Sujet :

Langage C++

  1. #1
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut Template de pointeur sur fonction (presque) générique
    Bonjour à tous,

    J'ai écrit un foncteur générique qui permet de créer facilement un foncteur de comparaison à utiliser dans std::set ou std::map en écrivant le moins de code possible :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template<typename T, typename I, I (T::*F)() const>
    struct mem_fun_comp_t {
        bool operator () (const T& t1, const T& t2) const {
            return (t1.*F)() < (t2.*F)();
        }
    };
    On l'utilise alors comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // classe de test
    struct test {
        const std::string name_;
        const int         id_;
     
        const std::string& name() const { return name_; }
        int                id()   const { return id_; }
    };
     
    // 's1' est trié selon 'name'
    std::set<test, mem_fun_comp_t<test, const std::string&, &test::name>> s1;
    // 's2' est trié selon 'id'
    std::set<test, mem_fun_comp_t<test, int, &test::id>> s2;
    Le problème est qu'on doit fournir deux informations redondantes en paramètres de mem_fun_comp_t : la classe test d'une part, et le type de la valeur comparée (const std::string& ou int) d'autre part, qui font toute deux partie de la signature de la fonction membre passée en troisième paramètre.

    Je cherche donc un moyen d'éviter cette lourdeur. La seule solution que j'ai trouvée jusqu'à présent, et que je n'aime pas trop, est de recourir à une macro :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // extraire la classe qui possède la fonction membre
    template<typename T, typename I>
    T mem_fun_owner(I (T::*f)() const) { return std::declval<T>(); }
     
    // extraire le type de la valeur comparée
    template<typename T, typename I>
    I mem_fun_return_type(I (T::*f)() const) { return std::declval<I>(); }
     
    // la macro
    #define mem_fun_comp(f) mem_fun_comp_t<decltype(mem_fun_owner(f)), decltype(mem_fun_return_type(f)), f>
    On l'utilise alors comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    // 's1' est trié selon 'name'
    std::set<test, mem_fun_comp(&test::name)> s1;
    // 's2' est trié selon 'id'
    std::set<test, mem_fun_comp(&test::id)> s2;
    Voyez-vous une autre solution qui n'utilise pas de macro ?

    HS : ce qui est sympa, c'est qu'on peut écrire quelque chose de très similaire pour trier selon une variable membre, sans avoir besoin de définir un accesseur (à condition que cette variable soit publique, bien entendu) :
    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
    template<typename T, typename I, I T::*V>
    struct mem_var_comp_t {
        bool operator () (const T& t1, const T& t2) const {
            return t1.*V < t2.*V;
        }
    };
     
    template<typename T, typename I>
    T mem_var_owner(I T::* v) { return std::declval<T>(); }
     
    template<typename T, typename I>
    I mem_var_type(I T::* v) { return std::declval<I>(); }
     
    #define mem_var_comp(v) mem_var_comp_t<decltype(mem_var_owner(v)), decltype(mem_var_type(v)), v>
     
    // 's1' est trié selon 'name'
    std::set<test, mem_var_comp(&test::name_)> s1;
    // 's2' est trié selon 'id'
    std::set<test, mem_var_comp(&test::id_)> s2;
    Ça m'a fait découvrir pour la première fois une utilité aux pointeurs sur variables membres

  2. #2
    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
    Bonsoir,

    En C++11 tu peux t'en sortir avec decltype et une fonction : tu fais une fonction template qui prend en paramètre ton pointeur de fonction et qui retourne ton type, puis par dessus tu mets un decltype sur l'appel pour récupérer le type de retour. L'appel permet de déduire automatiquement tout les types, et decltype de récupérer ce que tu veux.

    En C++03 je n'ai pas d'idée comme ça, ceci dit l'utilisation des pointeurs dans les template ne m'a jamais convaincu, je ne leur trouve aucun intérêt réel (si ce n'est pour du SFINAE, mais c'est loin d'être une utilisation régulière).

  3. #3
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    J'irais même plus loin...

    Etant donné que ta structure présente deux fonctions qui n'ont strictement rien en commun, pourquoi vouloir absolument faire quelque chose de générique

    Pourquoi ne pas faire tout simplement deux foncteurs différents, quitte à les utiliser, par la suite, comme politique dans quelque chose de plus générique


    Après tout, le principe de la programmation générique est de se dire que l'on ne sait peut etre pas quel type on va manipuler, mais que l'on sait, en retrour, parfaitement comment on va le manipuler.

    On peut donc parfaitement avoir des foncteurs génériques proches 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
    16
    17
    18
     
    /** @pre Type dispose d'une fonction "name" */
    template <typename Type>
    struct lessByName{
        bool operator()(Type const & first, Type const & second) const{
            return first.name() < second.name();
        }
    };
    /** @pre Type dispose d'une fonction "id" */
    template <typename Type>
    struct lessById{
        bool operator()(Type const & first, Type const & second) const{
            return first.id() < second.id();
        }
    };
    /* on peut avoir autant de foncteur que l'on veut, basés chaque fois sur
     * le prérequis de l'existence d'une fonction donnée ;)
     */
    Après, bien sur, rien ne t'empêche d'avoir ta propre classe qui prendrait la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     //par défaut, considérons que tous les objets ont une fonction "id" ;))
    template <typename Key, typename Value, typename Comp = lesById>
    class MaClass{
     
        private:
            std::map<Key, Value, Comp> items;
    };
    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

  4. #4
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    Comme on peut le voir dans les bouts de code que j'ai cité, je ne cherche pas à rester compatible avec le C++03 (le reste de mon code ne l'est pas, de toute façon).

    En revanche pour ta solution C++11, n'est-ce pas déjà ce que fait ma macro ?

    Je peux reformuler ma question : est-il possible d'écrire une classe template bar générique telle que le code ci-dessous soit valide quelle que soit la signature de la fonction foo :
    Posé comme ça, je pense que la réponse est non, car on est obligé de connaître le type de la variable avant de la déclarer dans la liste des paramètres templates :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template<typename Type, Type Value>
    struct bar {};
    et il faudrait donc carrément modifier le langage pour permettre quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template<auto Value>
    struct bar {};
    qui serait équivalent au code juste au dessus, à ceci près que la déduction du type est automatique.

  5. #5
    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
    En effet c'est ce que tu fais (je n'avais pas regarder ton code en détail). D'un point de vue purement technique, je ne vois rien de plus à faire. Désolé pour ces 2 interventions assez peu utile au final .

  6. #6
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Citation Envoyé par Kalith Voir le message
    Comme on peut le voir dans les bouts de code que j'ai cité, je ne cherche pas à rester compatible avec le C++03 (le reste de mon code ne l'est pas, de toute façon).

    En revanche pour ta solution C++11, n'est-ce pas déjà ce que fait ma macro ?

    Je peux reformuler ma question : est-il possible d'écrire une classe template bar générique telle que le code ci-dessous soit valide quelle que soit la signature de la fonction foo :
    Posé comme ça, je pense que la réponse est non, car on est obligé de connaître le type de la variable avant de la déclarer dans la liste des paramètres templates :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template<typename Type, Type Value>
    struct bar {};
    et il faudrait donc carrément modifier le langage pour permettre quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template<auto Value>
    struct bar {};
    qui serait équivalent au code juste au dessus, à ceci près que la déduction du type est automatique.
    Ca ressemble a std/boost::result_of (j'ai quelques problemes avec celui de boost aujourd'hui...), ou tu dois donner le type de l'appelant et les paramettres pour savoir de quel appel on parles si c'est un object appellable qui aurait plusieurs surcharches.

  7. #7
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    @Flob90: Merci quand même

    @Koala: Pardon, je n'avais pas vu ton message (qui est arrivé pendant que j'écrivais ma réponse).

    Citation Envoyé par koala01 Voir le message
    Pourquoi ne pas faire tout simplement deux foncteurs différents, quitte à les utiliser, par la suite, comme politique dans quelque chose de plus générique
    C'est une autre solution oui, mais si j'en suis venu à écrire ce genre de code, c'est j'ai l'impression d'écrire sans cesse le même genre de foncteur où seul le nom de la fonction change. Et comme je déteste me répéter, j'aimerai trouver une solution générique où je n'ai à écrire que le strict minimum à chaque fois.

    En plus, je n'ai montré qu'un petit bout de l'iceberg : dans mon code réel, j'utilise ces foncteurs de comparaison dans un conteneur perso (inspiré de Why You Shouldn't Use set, and What You Should Use Instead), dans lequel je permets la recherche d'éléments par clé plutôt que par valeur (ce que ne permet pas std::set).
    Pour que ça fonctionne, il faut que j'écrive par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    template <typename Type>
    struct lessByName{
        bool operator()(Type const & first, Type const & second) const{
            return first.name() < second.name();
        }
        bool operator()(Type const & first, std::string const & second) const{
            return first.name() < second;
        }
        bool operator()(std::string const & first, Type const & second) const{
            return first < second.name();
        }
    };
    Pour en rajouter une couche, mes objets sont rarement stockés comme valeurs, mais plutôt sous forme de pointeurs, nus ou std::unique_ptr. De façon à gérer ça de manière automatique, je peux utiliser un foncteur générique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    template <typename Type>
    struct lessByName{
        bool operator()(Type const & first, Type const & second) const{
            return first.name() < second.name();
        }
        bool operator()(Type const * first, Type const * second) const{
            return first->name() < second->name();
        }
        bool operator()(std::unique_ptr<Type> const & first, std::unique_ptr<Type> const & second) const{
            return first->name() < second->name();
        }
    };
    Si tu combines toutes ces options, le code réel de mem_fun_comp_t que j'introduis dans mon premier post est en réalité :
    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
    template<typename T, typename I, I (T::*F)() const>
    struct mem_fun_comp_t {
        using key_t = typename std::remove_cv<I>::type;
     
        bool operator () (const T& t1, const T& t2) const {
            return (t1.*F)() < (t2.*F)();
        }
     
        bool operator () (const T& t1, const key_t& t2) const {
            return (t1.*F)() < t2;
        }
     
        bool operator () (const key_t& t1, const T& t2) const {
            return t1 < (t2.*F)();
        }
     
        bool operator () (const T* t1, const T* t2) const {
            return (*t1.*F)() < (*t2.*F)();
        }
     
        bool operator () (const T* t1, const key_t& t2) const {
            return (*t1.*F)() < t2;
        }
     
        bool operator () (const key_t& t1, const T* t2) const {
            return t1 < (*t2.*F)();
        }
     
        bool operator () (const std::unique_ptr<T>& t1, const std::unique_ptr<T>& t2) const {
            return (*t1.*F)() < (*t2.*F)();
        }
     
        bool operator () (const std::unique_ptr<T>& t1, const key_t& t2) const {
            return (*t1.*F)() < t2;
        }
     
        bool operator () (const key_t& t1, const std::unique_ptr<T>& t2) const {
            return t1 < (*t2.*F)();
        }
    };
    Je pense que tu comprendras que je n'ai pas spécialement envie de ré-écrire tout ça à chaque fois que je voudrai faire un tri par rapport à une fonction membre qui porte un nom différent

    @Klaim: Hum pas tout à fait, il me semble que std::result_of ne travaille que sur des types, pas sur des pointeurs de fonction directement.

  8. #8
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Citation Envoyé par Kalith Voir le message
    @Klaim: Hum pas tout à fait, il me semble que std::result_of ne travaille que sur des types, pas sur des pointeurs de fonction directement.
    Oui il faut le type mais ca reste plus court que ta solution et deja implemente:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int top();
     
    std::result_of<decltype(top)>::type k = 42;
    Si tu arrives a ce qu'on puisse ecrire ca, ca sera plus court que tes fonctions non? (il se peut que j'ai rien compris, il est assez tard...)

    Les autres cas:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
     
    struct U{ int operator()(); };
     
    std::result_of<U()>::type k = 42;
     
     
    auto F = []{ return 42; };
     
    std::result_of<decltype(F)()>::type k = 42;

  9. #9
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    Ce que je cherche c'est justement d'avoir la valeur du pointeur sur la fonction en tant qu'unique paramètre template, et pas le type de cette fonction
    std::result_of m'aurait intéressé (enfin, la façon dont il aurait été implémenté) s'il pouvait prendre comme argument directement un pointeur, et non un type. Je ne sais pas si c'est très clair...

  10. #10
    Membre régulier
    Homme Profil pro
    Ingénieur
    Inscrit en
    Octobre 2006
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Transports

    Informations forums :
    Inscription : Octobre 2006
    Messages : 48
    Points : 97
    Points
    97
    Par défaut
    Bonsoir,

    J'ai essayé de retourner le problème en vain. Voir mon code ci-dessous :

    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
    #include <set>
    #include <string>
     
    // classe de test
    struct test {
        const std::string name_;
        const int         id_;
     
        const std::string& name() const { return name_; }
        int                id()   const { return id_; }
    };
     
    template <typename Func>
    struct member_of {};
     
    template <typename T, typename U>
    struct member_of<T U::*> {
        typedef U class_type;
        typedef T return_type;
    };
     
    template < typename Func, Func func,
             typename T = typename member_of<Func>::class_type,
             typename I = typename member_of<Func>::return_type >
    struct mem_fun_comp_t {
        bool operator () (const T& t1, const T& t2) const {
            return (t1.*func)() < (t2.*func)();
        }
    };
     
    #define mem_fun_comp(func) mem_fun_comp_t<decltype(func),func>
     
    int main()
    {
        // 's1' est trié selon 'name'
        std::set<test, mem_fun_comp_t<decltype(&test::name), &test::name>> s1;
        // 's2' est trié selon 'id'
        std::set<test, mem_fun_comp(&test::id)> s2;
     
        return 0;
    }
    schmilblick++

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Ce qu'il faut se rappeler, c'est que le type de retour est la seule chose:
    • qui ne peut pas (pour l'instant en tout cas) être déterminée automatiquement
    • qui n'entre pas dans directement dans l'évaluation du prototype d'une fonction
    Même std::function nécessite d'avoir au minimum un argument template pour le type de retour

    On pourrait donc, sans doute, simplifier un peu les choses en utilisant, justement, std::function, mais il faudrait toujours que tu précises le type de retour de la fonction à utiliser

    Ceci dit, peut etre que mem_fn pourrait te venir bien à point
    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

  12. #12
    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
    @koala01> decltype répond très bien à cette problématique.

    @all> Le problème c'est de prendre directement un pointeur de fonction quelconque en paramètre. A ma connaissance on ne peut pas faire ça sans introduire un appel avec un decltype comme l'a fait l'op. L'appel permettant de profiter de la déduction automatique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    decltype(my_fun(&fun_ptr));)
    Voila le plus court que tu peux avoir AMA. Après tu dois rajouter une macro.

  13. #13
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    J'ai du mal à comprendre ton exemple Flob90, peux-tu expliciter un peu plus ?

  14. #14
    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 pensais à un truc qui malheureusement ne marche pas (on ne peut utiliser que les types pour le decltype de retour). J'ai pu avoir :
    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<class T, class I>
    struct mem_fun_comp_t{
        template<I(T::*F)()const>
        struct type{
            bool operator()(const T& t1, const T& t2)const{
                return (t1.*F)()<(t2.*F)();
            }
        };
    };
     
    template<class T, class I>
    mem_fun_comp_t<T,I> men_fun_comp(I(T::*)()const);
     
    decltype(men_fun_comp(&test::name))::type<&test::name> a;
    On a cependant toujours une répétition, mais je ne pense pas qu'il soit possible de totalement les éliminer sans macro.

  15. #15
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    Ok je vois, ça ne va pas plus loin que ce qu'avait proposé iNaKoll par exemple. Merci d'avoir essayé en tout cas

  16. #16
    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
    Oui, je pensais à ça au départ :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    template<class T, class I, I(T::*F)()const>
    struct mem_fun_comp_t{
        bool operator()(const T& t1, const T& t2)const{
            return (t1.*F)()<(t2.*F)();
        }
    };
     
    template<class T, class I>
    auto men_fun_comp(I(T::*F)()const)
        ->mem_fun_comp_t<T,I,F>;
     
    decltype(men_fun_comp(&test::name)) a;
    Sauf que j'avais perdu de vue qu'on ne peut utiliser que les types, mais pas le paramètre F. Donc mon type de retour est invalide.

  17. #17
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Ceci dit, est ce que quelque chose comme
    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
    #include <string>
    #include <iostream>
    #include <functional>
    struct Data{
      std::string name_;
      int id_;
      std::string const & name() const{return name_;}
      int id() const{return id_;}
    };
    template <typename Type, typename Ret>
    struct Comp{
            typedef std::function<Ret(Type)>const fun;
            Comp(fun &f):f(f){}
            fun &f;
            bool operator()(Type const & first, Type const & second){
                return f(first) < f(second);
            }
    };
    int main(){
        Comp < Data, std::string> byName(&Data::name);
        Comp < Data, int> byId(&Data::id);
     
        Data one;
        one.name_ = "salut";
        one.id_ = 100;
        Data two;
        two.name_="world";
        two.id_=10;
        if(byName(one,two)){
            std::cout<<one.name()<<"<"<<two.name()<<std::endl;
        } else{
            std::cout<<one.name()<<">="<<two.name()<<std::endl;
        }
     
        if(byId(one,two)){
            std::cout<<one.id()<<"<"<<two.id()<<std::endl;
        } else{
            std::cout<<one.id()<<">="<<two.id()<<std::endl;
        }
        return 0;
    }
    pourrait éventuellement correspondre à ce que tu recherches?
    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

  18. #18
    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
    @koala01: Je pense que l'op a déjà envisagé ceci, mais il était dans l'idée de le faire directement en template. Ceci dit, c'est bien ce que je ferais aussi, les pointeurs de fonction en paramètre template c'est pas franchement la joie à utiliser je trouve.

  19. #19
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Mais il ne faut pas oublier que
    • void (*ptr)() correspond déjà à quelque chose de différent de void (T::*ptr)()
    • void (*ptr)(Type1) correspond déjà à quelque chose de différent de void (*ptr)(Type2)
    • et que void (*ptr)() correspond déjà à quelque chose de différent de int (*ptr)()
    Avec les pointeurs de fonctions, tu as donc trois "points de variation" possibles:
    1. le type de retour
    2. le type au départ duquel appeler la fonction (si ce n'est pas une fonction libre)
    3. le nombre et le type des arguments
    A partir du moment où tu veux pouvoir choisir "n'importe quel accesseur" afin d'effectuer le tri, il faut donc forcément indiquer le type de retour de cet accesseur, car il est purement et simplement impossible de le déduire à la compilation
    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

  20. #20
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Je pense que ton problème est lié à : http://www.open-std.org/jtc1/sc22/wg...013/n3601.html

    Ce papier a été reçu positivement, mais a été jugé non prêt pour C++14, et la syntaxe utilisée ne fait pas l'unanimité. Donc peut-être qu'en 2017 ou plus tard, ton problème aura une solution plus propre...
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Variadic template et pointeur sur fonction
    Par jetSett dans le forum Langage
    Réponses: 5
    Dernier message: 14/02/2013, 20h57
  2. Réponses: 4
    Dernier message: 15/07/2011, 13h04
  3. pointeurs sur fonction en C++
    Par cemoi dans le forum C++
    Réponses: 7
    Dernier message: 29/11/2004, 13h19
  4. [langage] Pointeur sur fonction
    Par Fanch.g dans le forum Langage
    Réponses: 2
    Dernier message: 02/10/2004, 10h43
  5. Declaration de fonction retournant un pointeur sur fonction
    Par pseudokifaitladifférence dans le forum C
    Réponses: 5
    Dernier message: 11/08/2003, 19h37

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