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

C++ Discussion :

Variadic templates et std::function


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut Variadic templates et std::function
    Bonjour,

    Je cherche à faire marcher un code du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    template<typename... args>
    int func(std::function<int(args...)> f)
    {
       return sizeof...(args); // juste pour tester
    }
    Avec ensuite :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    int f2(int a, int b, int c)
    {
        return a + b + c;
    }
    Le code suivant compile bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    std::function<int(int, int, int)> f3 = f2;
    func(f3); // renvoie bien 3
    En revanche, celui-ci ne compile pas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    func(f2); /* error: no matching function for call to ‘func(int (&)(int, int, int))’
    test.cpp:45:25: note: candidate is:
    test.cpp:28:5: note: template<class ... args> int func(std::function<int(args ...)>)
    test.cpp:28:5: note:   template argument deduction/substitution failed:
    test.cpp:45:25: note:   mismatched types ‘std::function<int(args ...)>’ and ‘int (*)(int, int, int)’ */
    Et celui-ci non plus :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    func([](int a, int b, int c) { return f2(a,b,c); }); /* error: no matching function for call to ‘func(main()::<lambda(int, int, int)>)’
    test.cpp:44:68: note: candidate is:
    test.cpp:28:5: note: template<class ... args> int func(std::function<int(args ...)>)
    test.cpp:28:5: note:   template argument deduction/substitution failed:
    test.cpp:44:68: note:   ‘main()::<lambda(int, int, int)>’ is not derived from ‘std::function<int(args ...)>’ */
    Pour le premier cas, je peux fournir un overload :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    template<typename... args>
    int func(int (*f)(args...))
    {
        return sizeof...(args);
    }
    Pas très élégant, mais ça marche. En revanche, pour le deuxième cas, je ne vois pas comment faire sans fournir l’ensemble des surcharges jusqu’à n arguments, ce qui est justement ce que je souhaitais éviter avec les templates variadic.

    Mon compilateur est gcc 4.7.2, je ne peux pas en changer. Des suggestions ?

  2. #2
    Membre émérite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2014
    Messages
    345
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

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

    Informations forums :
    Inscription : Juin 2014
    Messages : 345
    Par défaut
    Bonjour,

    Dans ton exemple, tu renvoies les nombre de paramètres de la fonction avec pour commentaire "juste pour tester".
    Quel est le but réel derrière ce test ?
    Il y a plusieurs manières de gérer ce genre de problèmes mais pour ça il faudrait voir qu'est-ce que c'est réellement censé faire au final.

  3. #3
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Dans le code réel, ça renvoie une lambda dont le rôle sera d’appeler f avec des paramètres lus depuis une structure, stockés temporairement dans un vecteur, après avoir vérifié un certain nombre de contraintes sur ces paramètres. En gros, l’idée, c’est de découpler la partie « récupération et vérification des paramètres » (qui viennent d’appels jsonrpc), assez systématique et répétitive, de la partie métier, et de la faire de manière générique (vérification de présence et type de chacun des arguments, appel de la fonction métier avec les arguments individuels si ok, sinon erreur).

    Oui, c’est un petit peu compliqué, c’est pour ça que j’ai essayé de simplifier au maximum pour montrer le point qui me bloque actuellement.

  4. #4
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    Salut,

    Pourquoi pas quelque chose dans cette veine :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template<class Fun>
    int func(Fun f)
    {
       return boost::function_traits<Fun>::arity; // pas sur de la syntaxe mais bon l'idée est là.
    }
    L'idée est d'être simplement plus général. D'habitude c'est de cette manière qu'on passe des fonctions en argument.

  5. #5
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Effectivement, j’avais négligé cette possibilité (du fait que j’ai certains paramètres fixés, le type de la valeur de retour fixé, etc).

    Néanmoins, ce n’est pas bon quand même :
    test.cpp: In instantiation of ‘int func(Fun) [with Fun = main()::<lambda(int, int, int)>]’:
    test.cpp:57:68: required from here
    test.cpp:43:53: error: ‘value’ is not a member of ‘boost::function_types::function_arity<main()::<lambda(int, int, int)> >’
    (pour les non lambdas, ça fonctionne bien).

  6. #6
    Membre Expert

    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
    Par défaut
    Pour la question initiale, la réponse devient clair si tu te mets à la place du compilateur. On te donne un truc de type A et tu dois le faire matcher avec un type B<T>, tu fais comment ? Comment tu peut savoir à l'avance si un B<T0> va proposer un constructeur depuis un A ? Tu ne peux pas (tout tester n'est pas envisageable (*)). Quand tu lui passes un A=B<T0> la problématique disparaît puisqu'on trouve un T qui fait parfaitement correspondre les types (**).

    Ta problématique de fond, c'est vraiment l'arité ? Parce que je ne suis pas convaincu qu'il y ai une vraie solution à cette problématique. Si je passe un foncteur polymorphe avec un Arg... qui fait du forward, la fonction fait quoi ? Cependant, si la question c'est vraiment l'arité, c'est une méta-fonction (***) qu'il faut chercher à faire, pas une fonction (c'est purement compile-time comme information).

    (*) Surtout qu'il faudrait ordonner les différentes possibilités ensuite ...
    (**) Modulo le const, volatile, &, &&, mais le compilateur les ignore pour la procédure de correspondance.
    (***) Dans l'idée il faut que tu envisages tout les cas possibles (que tu veux traiter) de foncteur, que tu fasses un my_meta_fn<> spécialisé pour chacun de ces cas avec un Arg... sur lequel faire un sizeof...(Arg).

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 30/05/2011, 19h38
  2. Réponses: 2
    Dernier message: 10/01/2009, 13h38
  3. Problème de class template et std::map
    Par bathof dans le forum Langage
    Réponses: 2
    Dernier message: 31/07/2007, 22h18
  4. template et std::vector
    Par themadmax dans le forum Langage
    Réponses: 9
    Dernier message: 26/07/2006, 10h41

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