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 :

appel de fonction boost::fusion::vector


Sujet :

C++

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Points : 345
    Points
    345
    Par défaut appel de fonction boost::fusion::vector
    Bonjour à tous,

    J'ai une fonction qui prend plusieurs paramètres par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void f(int a, doube b, std::string const& s);
    J'ai également un boost::fusion::vector "matchant ces paramètres:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef vector<int, double, std::string> vector_params_f;
    Est-il possible d'appeler f avec un vector_params_f ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main()
    {
      vector_params_f v;
      at_c<0>(v) = 10;
      f(v);
    }
    Si vous avez des pistes je suis preneur!

  2. #2
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Bonsoir,

    boost::fusion::invoke est une première solution :

    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
    #include <boost/fusion/functional/invocation/invoke.hpp>
    #include <boost/fusion/container/vector.hpp>
     
    #include <string>
     
    void f(int a, double b, std::string const& s)
    {
    }
     
    typedef boost::fusion::vector<int, double, std::string> vector_params_f;
     
    int main()
    {
      vector_params_f v;
      boost::fusion::at_c<0>(v) = 10;
     
      boost::fusion::invoke(&f, v);
    }
    Une deuxième solution : boost::fusion::fused

    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
     
    #include <boost/fusion/include/make_fused.hpp>
    #include <boost/fusion/container/vector.hpp>
     
    #include <string>
     
    void f(int a, double b, std::string const& s)
    {
    }
     
    typedef void (*fFunc)(int, double, std::string const&);
    typedef boost::fusion::vector<int, double, std::string> vector_params_f;
     
    int main()
    {
      vector_params_f v;
      boost::fusion::at_c<0>(v) = 10;
     
      boost::fusion::fused<fFunc> fused_f = boost::fusion::make_fused(&f);
      fused_f(v);  
    }
    edit : boost::fusion::fused est une solution très générale d'ailleurs. Si j'ai bien compris, c'est en fait un wrapper sous forme de fonction-objet polymorphique (comme std::function). On le construit en passant dans son constructeur l'objet "callable" que l'on veut appeler plus tard (pointeur de fonction, fonction-objet) qui est alors stocké dans le wrapper. Puis l'on appelle l'opérateur() en passant ce que la doc de fusion appelle une "séquence" (c'est à dire en fait un tuple comme boost::tuple ou boost::fusion::vector) et hop le wrapper se charge automatiquement de dépacker notre tuple et d'appeler la fonction originale en faisant matcher ses paramètres avec les composants du tuple.

    Edit 2 : Arf je viens de regarder le code de l'opérator() de boost::fusion::fused, et sans surprise il ne fait en fait qu'appeler fusion::invoke avec l'objet callable stocké et la séquence passé en paramètre.

    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
    template <typename Function>
    class fused
    {
        Function fnc_transformed;
     
        typedef typename detail::qf_c<Function>::type & func_const_fwd_t;
        typedef typename detail::qf<Function>::type & func_fwd_t;
     
        //...
       template <class Seq> 
       inline typename result_of::invoke<func_fwd_t,Seq>::type 
       operator()(Seq & s) 
      {
         return fusion::invoke<func_fwd_t>(this->fnc_transformed,s);
      }
    }

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Points : 345
    Points
    345
    Par défaut
    Bonjour,

    Merci Arzar pour ton aide, j'ai cependant encore un problème d'utilisation de ces méthodes: à la base mon idée était de faire une fonction fabrique de shared_ptr à partir de paramètres stockés dans des boost::fusion::vector:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template<typename FusionVector, typename T>
    boost::shared_ptr<T> my_make_shared(FusionVector const& v)
    {
       return boost::fusion::make_fused(&boost::make_shared<T>)(v);
    }
    mais lorsque j'essaie de compiler le code (complet) suivant:
    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
    #include <string>
    #include <boost/make_shared.hpp>
    #include <boost/fusion/include/vector.hpp>
    #include <boost/fusion/include/make_fused.hpp>
     
     
    struct A
    {
       A(std::string const& s, int i) {}
    };
     
     
    template<typename FusionVector, typename T>
    boost::shared_ptr<T> my_make_shared(FusionVector const& v)
    {
       return boost::fusion::make_fused(&boost::make_shared<T>)(v);
    }
     
    int main()
    {
       typedef boost::fusion::vector<std::string, int> fusion_vector_a;
     
       fusion_vector_a params_a;
     
       boost::shared_ptr<A> a(my_make_shared<fusion_vector_a, A>(params_a));
    }
    J'ai une erreur de compilation :
    >boost_1_49_0\boost/utility/result_of.hpp(82) : error C2825: 'F'*: doit être une classe ou un espace de noms lorsqu'il est suivi par '::'
    main.cpp(354)*: voir la référence à l'instanciation de la classe modèle 'boost::fusion::result_of::invoke<Function,Sequence>' en cours de compilation
    with
    [
    Function=boost::shared_ptr<A> (__cdecl &)(void),
    Sequence=const fusion_vector_a
    ]
    PS: je compile avec VS2008 et avec boost 1.49

  4. #4
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Désolé, je rends les armes sur ce coup là.
    Faudrait demander sur stack overflow.

    Le problème, je pense, c'est qu'on ne peut pas faire ça &boost::make_shared<T> vu qu'il y a en fait une quinzaine de fonction template surchargées make_shared (chacune avec un argument de plus)

    Après il reste la solution de de tout wrapper dans une fonction-objet, mais je suppose que c'est le genre de code que tu voulais éviter...
    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
     
    struct A
    {
       A(std::string const& s, int i) {}
    };
     
    template <typename T>
    struct LazyMakeShared
    {
    	typedef boost::shared_ptr<T> result_type;
     
    	template <typename T0>
    	boost::shared_ptr<T>
    	operator()(const T0& t0)
    	{
    		return boost::make_shared<T>(t0);
    	}
     
    	template <typename T0, typename T1>
    	boost::shared_ptr<T>
    	operator()(const T0& t0, const T1& t1)
    	{
    		return boost::make_shared<T>(t0, t1);
    	}
             //... etc
    };
     
    template<typename FusionVector, typename T>
    boost::shared_ptr<T> my_make_shared(FusionVector const& v)
    {
    	return boost::fusion::invoke(LazyMakeShared<T>(), v);
    }
     
    int main()
    {
       typedef boost::fusion::vector<std::string, int> fusion_vector_a;
     
       fusion_vector_a params_a;
     
       boost::shared_ptr<A> a(my_make_shared<fusion_vector_a, A>(params_a));
    }

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Points : 345
    Points
    345
    Par défaut
    Merci Arzar pour ton aide.

    J'ai pas trop eu le temps de m'y pencher aujourd'hui; je vais voir si je peux pas m'y prendre autrement. Sur le coup du make_shared j'ai pensé naïvement que le compilateur pourrais choisir la bonne version mais c'est lié au fait que quasiment toute mes classes n'ont qu'une signature de constructeur; dans le cas général, il ne peut pas trancher au moment du &make_shared<T>.

    Au pire je pourrais toujours passer par la solution que tu proposes (c'est pas hyper élégant mais ça allègera un peu mon code client). Après je ne m'y connais pas trop en macro mais il me semble qu'il doit être possible de dérouler la structure LazyMakeShared. Je vais essayer de voir de ce côté là.

    En tout cas merci encore à toi!

  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
    Tu peux te permettre le C++11 ? Dans ce cas tu dois pouvoir utiliser une approche avec des variadics templates.

    Sinon, alors il faut que tu le fasses à la main, l'idée va être de créer un foncteur polymorphe make_shared (qui remplacera la fonction), sans oublier le protocole result_of (pas en C++11, mais si tu parts dans cette direction c'est que tu n'utilises pas le C++11).

    Pour faire ça, tu peux le faire totalement à la main en utilisant boost::pp pour faire de la répétition verticale de code, il doit être aussi possible de déléguer une partie du travaille à boost::phoenix (cf actor), et dans ce cas tout ce qu'il y aura à écrire pour faire ce foncteur c'est quelques lignes de boost::pp servant à répéter une macro de boost::phoenix pour créer l'acteur pour une ensemble d'arité.

Discussions similaires

  1. [Boost.Function] Appeler une fonction "externe"
    Par poukill dans le forum Boost
    Réponses: 17
    Dernier message: 29/08/2007, 16h04
  2. [STL] vector<string> et appel de fonctions.
    Par guejo dans le forum MFC
    Réponses: 4
    Dernier message: 08/10/2004, 17h36
  3. [JSP] Appeler une fonction
    Par Patrick95 dans le forum Servlets/JSP
    Réponses: 10
    Dernier message: 23/12/2003, 13h44
  4. Appel à des fonctions incluses dans des DLL
    Par Greybird dans le forum Langage
    Réponses: 3
    Dernier message: 26/05/2003, 13h33
  5. Appeler une fonction avec/sans parenthèses
    Par haypo dans le forum Algorithmes et structures de données
    Réponses: 8
    Dernier message: 29/12/2002, 18h48

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