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++

  1. #1
    Membre émérite
    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
    Points : 2 799
    Points
    2 799
    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 éprouvé
    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
    Points : 1 211
    Points
    1 211
    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 émérite
    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
    Points : 2 799
    Points
    2 799
    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 expérimenté 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
    Points : 1 396
    Points
    1 396
    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 émérite
    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
    Points : 2 799
    Points
    2 799
    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
    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
    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).

  7. #7
    Membre émérite
    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
    Points : 2 799
    Points
    2 799
    Par défaut
    Je comprends le compilateur, mais j’ai quand même un manque (soit dans mon compilateur, soit dans le langage, soit dans ma connaissance de celui-ci, mais le fait que ça ne fonctionne pas non plus chez boost m’incite à pencher pour une des deux premières propositions).

    Le manque, c’est la capacité de faire une spécialisation template pour une lambda dont on connaîtrait les arguments et le type de retour. Je peux le faire pour un std::function et un pointeur de fonction, mais pas une lambda. C’est un peu dommage.

    Sinon, ma problématique n’est pas l’arité (qui n’était que pour mettre en œuvre le manque), ma problématique est globalement de récupérer des arguments reçus dans une map et de rappeler une fonction avec les bons paramètres, après avoir fait un certain nombre de vérifications (en mode programmation défensive, justifié car on est dans un contexte web). Au final je m’en sors en fournissant les différentes surcharges possibles (et via un variant pour limiter le nombre de combinaisons). J’aurais aimé faire sans (ie, faire générer chaque variante par le compilateur), mais j’ai du mal à voir comment.

    Le pseudo-code suivant reproduit grosso-merdo ce que j’essaie de faire :
    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
     
    std::function<int(std::map<std::string, variant> const&)>
    createFunctor(std::map<std::string, ParamDescription> const& paramDescription, std::function f)
    {
       return [paramDescrition](std::map<std::string, variant> parameters)
       {
             for(param : paramDescription)
             {
                   if(/* everything ok with param, found in parameters with good type, etc... */)
                       accumulate(parameters[param.name];
             }
             if(everythingOk)
                 return f(param1, param2, param3…)
             else
                 report error;
       }
    }
    Pour l’instant j’accumule les paramètres dans une array et je les envoie en tant que variant. Comme je spécialise pour chaque nombre d’arguments, ça passe, et comme ma fonction n’est plus template, je profite de la conversion de ma lambda vers std::function, qui fait que ça fonctionne bien aussi. Mais c’est lourd puisque je dois créer explicitement pour chaque nombre d’arguments (soit actuellement 6*fonctions à maintenir), et idéalement chaque type de mon variant (ce qui donnerait à la louche 5^6 implémentations, ce qui n’est pas envisageable).

  8. #8
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Tu as besoin de passer explicitement par des lambdas?
    Tu ne pourrai pas les convertir en std::function avant de les donner à ta fonction?
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  9. #9
    Membre émérite
    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
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par leternel Voir le message
    Tu as besoin de passer explicitement par des lambdas?
    Tu ne pourrai pas les convertir en std::function avant de les donner à ta fonction?
    Je pourrais, mais au prix de la lisibilité du code client. Et j’ai parlé de lambdas, mais ça peut aussi être le résultat de std::bind (mais même remarque, on peut le mettre dans un std::function). Au final, ce n’est pas très satisfaisant non plus (je préfère en rester à mes 6 « spécialisations » écrites à la main pour l’instant).

  10. #10
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Pourquoi ne pas mettre la fonction en tant qu'argument template et passer par des tags pour la spécialisation (proto<result_type, nb_argument> ou autres) ?

  11. #11
    Membre émérite
    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
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par jo_link_noir Voir le message
    Pourquoi ne pas mettre la fonction en tant qu'argument template et passer par des tags pour la spécialisation (proto<result_type, nb_argument> ou autres) ?
    Peux-tu détailler ? Je ne suis pas sûr de voir où tu veux en venir.

  12. #12
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Hello !

    Il est possible de faire cela, mais il faut ruser un peu en exploitant le fait qu'une lambda est un type qui possède un opérateur (). Voici un exemple (il y a plusieurs manière de s'y prendre) :

    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
    #include <functional>
    #include <iostream>
     
    template <typename Function> struct function_traits ;
     
    template <typename ClassType, typename ReturnType, typename... Args>
    struct function_traits<ReturnType(ClassType::*)(Args...) const> {
      using function = const std::function<ReturnType(Args...)>;
    };
     
    template<typename... args>
    int func(std::function<int(args...)> f)
    {
         return sizeof...(args);
    }
     
    template<typename T>
    typename std::enable_if<std::is_function<T>::value, int>::type
    func2(T const& f)
    {
         return func(std::function<T>(f));
    }
     
    template<typename T>
    typename std::enable_if<!std::is_function<T>::value, int>::type
    func2(T const& f)
    {
         return func( static_cast<typename function_traits<decltype(&T::operator())>::function>(f));
    }
     
    int f2(int a, int b, int c) { return a+b+c; }
     
    int main() {
      std::cout << func2(f2) << "\n";
      std::cout << func2([](int a, int b) { return a+b; }) << "\n";
    }
    Je ne l'ai pas fait dans l'exemple pour aller au plus court en collant à ton use case, mais le plus propre reste de se coder une fonction template to_function qui prend n'importe quoi et sort le std::function qui va bien, en utilisant la même technique que ci-dessus. Testé sur gcc 4.7.2 avec succès (tu serais pas coincé sous wheezy par hasard ?).

    Edit : une version réutilisable.
    Find me on github

  13. #13
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    C'est à peu de choses près la même idée. La seule différence est que function_trais servirait plus à créer un type prototype<Result(Args...)> pour l'envoyer en premier paramètre de func. Cela évite d'instancier un objet std::function qui est un peu lourd (vérification de l’existence d'une fonction, allocation dynamique, etc).

  14. #14
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Oui, je vois, une version générique avec un type qui représente la signature en somme ? C'est possible en effet, mais vu que l'op utilise un std::function dans tous les cas, c'est pas la peine de trop s'embêter .

    Autre remarque : on ne peut pas faire ça avec des bind expressions (résultatt de std::bind) car celles-ci peuvent supporter plusieurs surcharges dans une seule expression. De fait, pour pouvoir convertir une bind expression en std::function, il faut explicitement dire quelle surcharge on veut (même s'il n'y en a qu'une, hélas).
    Find me on github

  15. #15
    Membre émérite
    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
    Points : 2 799
    Points
    2 799
    Par défaut
    Bon, je commence à entrevoir quelques solutions, merci beaucoup pour vos suggestions !

    tu serais pas coincé sous wheezy par hasard ?
    Ça se voit tant que ça ?

  16. #16
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Ça se voit tant que ça ?
    gcc 4.7.2, c'est grillé. J'ai la même de mon côté .
    Find me on github

  17. #17
    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 pense avoir une piste qui pourrait t'aider.

    L'idée principale serait de se reposer sur boost::fusion::invoke qui prend en paramètre un foncteur et une séquence boost.fusion. Ton objectif est (si j'ai bien compris et en simplifiant) d'arriver à une fonction make_ qui à partir d'un foncteur te retourne un foncteur acceptant en entrée une séquence d'objet et retournant le foncteur appliqué à chaque élément de la séquence transformé ?

    Donc en reprenant fusion::invoke, le foncteur tu l'as. La problématique est sur la séquence boost.fusion, la taille d'une telle séquence doit être fixé à la compilation et les types des éléments aussi. En se restreignant aux foncteurs monomoprhique, à un nombre maximal de paramètre et un ensemble de types de données connus, on peut passer outre. Un code pour voir l'idée est plus clair que de longues phrases :
    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
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
     
    #include<string>
    #include<utility>
    #include<vector>
     
    #include<boost/fusion/container/vector.hpp>
    #include<boost/fusion/container/generation/make_vector.hpp>
    #include<boost/fusion/functional/invocation/invoke.hpp>
     
    namespace fusion = boost::fusion;
     
    struct A
    {};
     
    struct B
    {};
     
    //Un type intermédiaire pour aller des std::string aux paramètres
    struct sys_init
    {
    	sys_init(const std::string& s)
    		: str(s)
    	{}
     
            //C'est là que tu peux vérifier ce que tu veux avant de construire les objets
    	operator A() const
    	{ return A(); }
    	operator B() const
    	{ return B(); }
     
    private:
    	std::string str;
    };
     
    void foo(A){}
    void bar(B){}
     
    template<class F>
    std::function<void(const std::vector<std::string>&)>
    	make_adapt(F&& fun)
    {
    	return
    		[fun](const std::vector<std::string>& seq)
    		{
                            //Ici appel avec seulement un paramètre, si ca ne correspond ps erreur de compilation
    			fusion::invoke(fun,fusion::make_vector(sys_init(seq[0])));
     
    			//Vers du SFINAE et boost.pp pour tester jusqu'au nombre de paramètre voulu :
    			//call_or_ignore<fusion::vector<sys_init>>(fun,seq);
    			//call_or_ignore<fusion::vector<sys_init,sys_init>>(fun,seq);
    			//...
    		}
    	;
    }
     
    int main()
    {
           //De quoi stocker mes foncteur
    	std::vector<
    		std::function<void(const std::vector<std::string>&)>
    	> seq_fun;
    	seq_fun.reserve(2);
     
            //Une donnée d'entrée à passer à foo et bar
    	std::vector<std::string> seq_s {"a"};
     
    	seq_fun.push_back(make_adapt(foo));
    	seq_fun.push_back(make_adapt(bar));
     
            //Appel
    	seq_fun[0](seq_s);
    	seq_fun[1](seq_s);
    }
    J'ai regardé un peu pour faire le SFINAE, mais il n'est pas si trivial que ça à faire (certains éléments de boost supporte mal cette technique). Il faut aussi faire attention lors de l'écriture pour limiter les copies. Je vais continuer de regarder et je reposterais si j'avance un peu plus.

  18. #18
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    @Flob90: je pense que tu as confondu avec ce post.
    Find me on github

  19. #19
    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
    @jblecanard: Non, je me suis pas trompé. C'est juste que je préfère partir du "pseudo-code" de ce qu'il veut faire, que du problème technique de spécialisation, j'ai juste pas pris en compte std::map<std::string, ParamDescription> const& paramDescription et utilisé un const std::vector<std::string>& seq à la place d'une std::map<std::string, variant>.

  20. #20
    Membre émérite
    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
    Points : 2 799
    Points
    2 799
    Par défaut
    En fait, pour la deuxième partie (l’appel de la fonction), j’ai testé avec succès le template suivant, qui fonctionne avec une array mais aussi un tuple :

    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<const int n>
    struct f
    {
        template<typename Array, typename Fun, typename... Args>
        static auto call(Fun fun, Array const& arr, Args... arg) -> decltype(f<n-1>::call(fun, arr, std::get<n-1>(arr), arg...))
        {
            return f<n-1>::call(fun, arr, std::get<n-1>(arr), arg...);
        }
    };
     
    template<>
    struct f<0>
    {
        template<typename Array, typename Fun, typename... Args>
        static auto call(Fun fun, Array /*arr*/, Args... arg) -> decltype(fun(arg...))
        {
            return fun(arg...);
        }
    };
    Simple et efficace. En cumulant ça et le make_function, je dois pouvoir m’en sortir en spécialisant très peu de code (juste le make_function, en fait).

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

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