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 :

informations à la compilation pour une fonction membre


Sujet :

Langage C++

  1. #1
    Membre averti Avatar de vikki
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    292
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mai 2007
    Messages : 292
    Points : 302
    Points
    302
    Par défaut informations à la compilation pour une fonction membre
    Bonjour à tous,

    J'essaie de récupérer à la compilation le nombre d'arguments (et leur type) d'une fonction membre (en l'occurrence l'operateur()). Je ne vois pas comment m'y prendre, ni même si cela est possible (je suppose que oui). Je tripatouille un peu avec boost.function_types mais pas moyen de m'en sortir. En gros, j'aimerais avoir quelque chose comme:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template< class MyClass >
    struct bracket_operator_info
    {
       enum {arity = ... }
       typedef ... result_type;
       typedef ... arg1;
       .
       .
       .
    }
    Quelqu'un aurait-il une idée de la marche à suivre?

  2. #2
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    function_types::function_arity te renvoie une mpl integral constant définissant le nombre de paramètres.

    et function_types::parameter_types te renvoie une MPL sequence (random access)

  3. #3
    Membre averti Avatar de vikki
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    292
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mai 2007
    Messages : 292
    Points : 302
    Points
    302
    Par défaut
    Hello et merci de ta réponse.
    Je dois mal utiliser function_types. Pour l'instant, j'essaie ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    struct Test
    {
       int my_function(int val) {return val*2;}
    };
     
    int arity = boost::function_types::function_arity<&Test::my_function>::value;
    qui ne compile pas sous Visual 8 ('boost::function_types::function_arity'*: argument modèle non valide pour 'T', type attendu). Effectivement je passe un pointeur de fonction membre en paramètre, mais comment peut on faire autrement?

  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 : 34
    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
    Tu peux passer par une fonction intermédiaire qui grace aux template déduit le type en fonction de paramètre, quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    template<class T> size_t my_func(T)
    { return function_arity<T>::value; }
     
    //Utilisation
    my_func(&Test::my_function);
    Vérifie quand même que ca existe pas déjà dans boost.

    NB: J'ai pas boost sur la main pour tester que c'est bon, j'ai pris un function_arity de cette forme (avec variadic) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    template<class T>
    struct function_arity;
     
    template<class T, class R, class ...Arg>
    struct function_arity<R(T::*)(Arg...)>
    { enum { value = sizeof...(Arg) }; };
    (Celui de boost est évidament plus complet, c'était juste pour tester dans un cas particulier), Il faudra peut-etre adapter si c'est pas exactement ce genre de paramètre que boost attend (cf la doc).

  5. #5
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Hum, ouai utilise une function template. Mais tu parler de travailler avec des function object dans ce cas là ça marchera pas. (function arity ne marche qu'avec les builtin Callable). Pourquoi? Parce que c'est "pas faisable", parce qu'un functor peut avoir plusieurs arités...

    Mais y'a moyen de s'en sortir, proto propose quelque chose :
    http://www.boost.org/doc/libs/1_45_0...function_arity

  6. #6
    Membre averti Avatar de vikki
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    292
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mai 2007
    Messages : 292
    Points : 302
    Points
    302
    Par défaut
    Bon, j'avance un peu.

    @Flob90:

    La fonction intermédiaire est une bonne idée, je ne savais pas qu'il était possible d'utiliser un sizeof sur un appel de fonction. En fait c'est ce que boost function_traits fait quand la macro BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION est définie (type_traits/function_traits.hpp). Du coup une réécriture pour les pointeur de fonction membre fonctionne pour déterminer l'arité (copié collé depuis function_traits.hpp avec qqes changements):


    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
     
    template<unsigned N> 
    struct type_of_size
    {
      char elements[N];
    };
     
    template<typename Class, typename R>
    type_of_size<1> member_function_helper(R (Class::*f)());
     
    template<typename Class,typename R, typename T1>
    type_of_size<2> member_function_helper(R (Class::*f)(T1));
     
    //etc...
     
    template<typename Class>
    struct member_function_traits
    {
    	BOOST_STATIC_CONSTANT(unsigned, arity = (sizeof(member_function_helper(&Class::operator()))-1));
    };
    J'imagine qu'on peut généraliser le tout en renvoyant directement un boost::function_traits et en utilisant BOOST_TYPEOF:

    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 Class, typename R>
    boost::function_traits<R()> member_function_helper(R (Class::*f)());
     
    template<typename Class, typename R, typename T1>
    boost::function_traits<R(T1)> member_function_helper(R (Class::*f)(T1));
     
    //etc...
     
    template<typename Class>
    struct member_function_traits
    {
    	typedef BOOST_TYPEOF(member_function_helper(&Class::operator())) function_traits_type;
    };
    Ça fait ce que je souhaite mais reste un peu lourd et probablement pas du tout optimal.


    @Goten:
    J'ai l'impression que tout est possible avec proto mais cela reste au delà de mon niveau pour l'instant. Merci pour le lien, je vais prendre qqes jours pour essayer de digérer tout ca .

  7. #7
    Membre averti Avatar de vikki
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    292
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mai 2007
    Messages : 292
    Points : 302
    Points
    302
    Par défaut
    En fait non, le BOOST_TYPEOF ne passe pas ('boost::function_traits<R(T1)> member_function_helper(R (__thiscall Class::* )(T1,T2))'*: impossible de déduire l'argument modèle pour 'R (__thiscall Class::* )(T1,T2)' à partir de 'T:)', et ce pour toutes les surcharges)...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template<typename T>
    struct m_function_traits
    {
    	typedef BOOST_TYPEOF_TPL(member_function_helper(&T::operator())) ff;
    };
    Alors que ce qui semble équivalent sous la forme d'une fonction passe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template<typename T>
    void test(){ typedef BOOST_TYPEOF_TPL(member_function_helper(&T::operator())) ff; }
    Je suis un peu perdu là

  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 : 34
    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 n'ai pas regardé en détails les codes que tu as mis, mais au vue de ton message tu n'as pas compris ce que j'ai posté :

    Cette partie là
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template<class T>
    struct function_arity;
     
    template<class T, class R, class ...Arg>
    struct function_arity<R(T::*)(Arg...)>
    { enum { value = sizeof...(Arg) }; };
    Je l'ai marqué car je n'avais pas boost sous la main et j'avais besoin de quelque chose pour tester avant de te proposer, tu n'as pas à le faire, c'est le function_arity de boost (ou presque, je l'ai mis au cas où tu ais besoin d'adapter pour savoir d'où je suis partie), du moins un petit bout d'un petit bout.
    (Et au passage, le sizeof s'applique pas sur un appel de fonction, il n'y a d'ailleurs pas de sizeof mais un sizeof... qui est une syntaxe introduite avec les variadics template pour récupérer le nombres de paramètre template dans un paquet de paramètre).

    La partie qui t'interesse est celle ci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template<class T> size_t my_func(T)
    { return function_arity<T>::value; }
    C'est une simple fonction template, qui grace au méchanisme de déduction des types template permet de déduire le type d'une expression passé en paramètre et d'appeler dessus le function_arity de boost. Cependant il y a un problème comme l'a soulevé Goten.

    Pour détailler un peu ce problème, typiquement il va se produire dans ce cas là :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    struct A {
      void foo() {}
      void foo(int) {} };
    En utilisant le code que j'ai mis au-dessus, naturellement tu ferais quelque chose comme :
    Le problème dans ce cas, c'est qu'il existe différente surcharges de foo, et que donc le compilateur ne peut pas déduire le type (avec les templates il ne faut pas oublier que le compilateur n'est pas un magicien, si tu ne peux pas prévoir le comportement de manière rationnel, il ne le pourra pas non plus !).

    C'est pour ce problème que Goten propose Proto (mais je peus pas t'en dire plus sur la solution), à toi de savoir si tu as besoin ou non de ce genre de cas).

    <Edit> Dans le code que tu as posté, le sizeof appliqué à une fonction retourne le sizeof appliqué au type de retour, c'est une technique classique de méta-prog et c'est un des éléments de bases pour implémenter un SFINAE.

    On pourrait produire quelque chose avec ceci qui te retournerait l'arité d'une fonction membre avec un certain nom d'une classe quelconque, puis ensuite d'une fonction membre quelconque avec une macro, mais ca ne te permettra pas de le faire à partir d'un pointeur sur la fonction. Et le problème des surcharges reste.
    </Edit>

    <Edit2>
    On pourrait faire ca dans l'esprit de ce que tu as posté comme code :
    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 Arity_foo
    {
      template<size_t t> struct wrapper { typedef char type[t]; };
      template<class R, class... Arg>
      static typename wrapper<sizeof...(Arg)+1>::type& helper(R (T::*)(Arg...));
     
      public:
        enum { value = sizeof(helper((&T::foo)))-1 };
    };
     
    //utilisation
    Arity_foo<my_class>::value;
    Mais les deux objectifs sont différents, l'un permet de récupérer l'arité à partir d'un pointeur sur la fonction membre, l'autre l'arité d'une fonction membre nommé foo dans la class T (et par généralisation avec des macros, d'une fonction membre d'un nom quelconque).
    A noter qu'il y a peut-etre dans boost quelque chose qui fait déjà ce travail, il faudrait vérifier. (Dans les outils de méta-prog, genre mpl)
    </Edit2>

  9. #9
    Membre chevronné
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Points : 1 921
    Points
    1 921
    Par défaut
    c'est un probleme dur. Y a pas e solution generale.
    La seule chose quu marche c'est le is_callable de proto qui reponds oui/non a la question: est-ce que F peut etre appelé avec A1,..,An en parametres.

  10. #10
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Sachant que pour qu'il fonctionne il faut d'abord filtrer pour ne garder que les types dérivables (funwrap2 dérive de Fun) et je ne crois pas qu'il n'existe de moyen ultime d'écarter les enums...

    MAT.

  11. #11
    Membre averti Avatar de vikki
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    292
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mai 2007
    Messages : 292
    Points : 302
    Points
    302
    Par défaut
    (Et au passage, le sizeof s'applique pas sur un appel de fonction, il n'y a d'ailleurs pas de sizeof mais un sizeof... qui est une syntaxe introduite avec les variadics template pour récupérer le nombres de paramètre template dans un paquet de paramètre).
    Au temps pour moi, je ne connaissais pas le sizeof... Mais cette méthode (utilisation d'une fonction de type template<class T> size_t my_func(T)) peut-elle permette de déterminer l'arité à la compilation?

    Le problème dans ce cas, c'est qu'il existe différente surcharges de foo, et que donc le compilateur ne peut pas déduire le type (avec les templates il ne faut pas oublier que le compilateur n'est pas un magicien, si tu ne peux pas prévoir le comportement de manière rationnel, il ne le pourra pas non plus !).
    J'avais bien conscience de ce problème et j'espère bien recevoir une erreur de compilation lorsque des surcharges seront présentes. Je souhaite forcer l'utilisateur à ne fournir qu'un prototype de l'opérateur ().

    Mais les deux objectifs sont différents, l'un permet de récupérer l'arité à partir d'un pointeur sur la fonction membre, l'autre l'arité d'une fonction membre nommé foo dans la class T (et par généralisation avec des macros, d'une fonction membre d'un nom quelconque).
    A noter qu'il y a peut-etre dans boost quelque chose qui fait déjà ce travail, il faudrait vérifier. (Dans les outils de méta-prog, genre mpl)
    C'est effectivement le but du code que j'avais posté (sans variadic, visual 8 oblige, avec les x surcharges à définir, probablement via preprocessor). L'utilisation d'une macro est une bonne idée, même si pour l'instant je me cantonne à l'opérateur() qui semble plus claire pour tous. Je n'ai rien trouvé dans boost sur les pointeurs de fonctions membres mais il me semble avoir surpris quelques messages les concernant sur la mailing list pour un éventuel ajout dans type_traits.

    Hum, ouai utilise une function template. Mais tu parler de travailler avec des function object dans ce cas là ça marchera pas. (function arity ne marche qu'avec les builtin Callable). Pourquoi? Parce que c'est "pas faisable", parce qu'un functor peut avoir plusieurs arités...
    Est ce vraiment impossible pour les function object? On ne pourrait pas imaginer la même méthode pour les pointeur de fonctions, références de fonctions, pointeurs sur données membres, et heu... Bon, ok c'est lourd. Sans parler de la surcharge qui casse tout.

    L'idée des x surcharges de type
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template<class R, class... Arg>
      static typename wrapper<sizeof...(Arg)+1>::type& helper(R (T::*)(Arg...));
    fonctionne tres bien et permet de spécialiser des classes, ce que je souhaitais à la base. Quant à récupérer les types des arguments, je peux m'en passer (d'autant plus que ca semble velu voir impossible).

    Merci pour vos réponses, je pense y voir plus clair.

Discussions similaires

  1. [QtConcurrent] QtConcurrent::run() pour une fonction membre
    Par silvio78 dans le forum Multithreading
    Réponses: 4
    Dernier message: 29/03/2010, 17h29
  2. Demande d'information SQL pour une fonction VRAIFAUX
    Par Fredy17 dans le forum Requêtes et SQL.
    Réponses: 3
    Dernier message: 14/03/2008, 02h07
  3. [Systeme d'Information] Quels conseils pour une refonte ?
    Par jejefeds dans le forum Décisions SGBD
    Réponses: 3
    Dernier message: 07/12/2005, 18h23
  4. paramètres pour une fonction
    Par bul dans le forum Général JavaScript
    Réponses: 5
    Dernier message: 28/05/2005, 07h49
  5. Thread avec une fonction membre d'une classe
    Par SteelBox dans le forum Windows
    Réponses: 6
    Dernier message: 01/03/2004, 01h15

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