boost mpl, passer une fonction dans un placeholder

boost mpl, passer une fonction dans un placeholder - C++ - Programmation

Marsh Posté le 13-09-2008 à 18:55:42    

Bonjour,
   Je cherche à faire les exercices proposés dans la doc de la mpl de boost. Et j'avoue avoir un problème avec le suivant :

Citation :

Build a lambda expression that has functionality equivalent to twice. Hint: mpl::apply is a metafunction!


twice prenant deux paramètres f et x et calcule (f o f)(x)
 
  Sans passer par une fonction anonyme on peux facilement faire ça :

Code :
  1. template<typename F, typename X>
  2. struct Twice_lambda :
  3.      boost::mpl::apply<F, typename boost::mpl::apply<F, X>::type >
  4. {};
  5. // et à l'utilisation
  6. typedef Twice_lambda<boost::add_pointer<_1>, int>::type calc_pointer;


 
Mon problème est sur la réalisation de la fonction lambda. Comme elle est anonyme je veux la mettre directement dans un boost apply comme ça:

Code :
  1. typedef boost::mpl::apply<
  2.      boost::mpl::apply<
  3.           _1,
  4.           typename boost::mpl::apply<_1, _2>::type
  5.      >,
  6.      boost::add_pointer<_>
  7.      , int
  8. >::type calc_pointer;


 
le problème c'est j'ai l'impression que le compilo se perd dans les placeholders. Il me sort :

Citation :


d:\libc++\boost_1_35_0\boost\mpl\aux_\preprocessed\plain\apply_wrap.hpp(48) : error C2039: 'boost::mpl::apply<F,T1>' : is not a member of 'boost::mpl::apply<F,T1>'
        with
        [
            F=boost::add_pointer<boost::mpl::_>,
            T1=int
        ]
        and
        [
            F=boost::mpl::_1,
            T1=boost::mpl::_2
        ]
        d:\libc++\boost_1_35_0\boost\mpl\aux_\preprocessed\plain\apply.hpp(63) : see reference to class template instantiation 'boost::mpl::apply_wrap2<F,T1,T2>' being compiled
        with
        [
            F=boost::mpl::apply<boost::mpl::_1,boost::mpl::_2>,
            T1=boost::add_pointer<boost::mpl::_>,
            T2=int
        ]
        d:\libc++\boost_1_35_0\boost\mpl\aux_\preprocessed\plain\apply.hpp(71) : see reference to class template instantiation 'boost::mpl::apply2<F,T1,T2>' being compiled
        with
        [
            F=boost::mpl::apply<boost::mpl::_1,boost::mpl::_2>,
            T1=boost::add_pointer<boost::mpl::_>,
            T2=int
        ]
        d:\projets\visual studio 2005\projects\metaprog\metaprog\main.cpp(50) : see reference to class template instantiation 'boost::mpl::apply<F,T1,T2>' being compiled
        with
        [
            F=boost::mpl::apply<boost::mpl::_1,boost::mpl::_2>,
            T1=boost::add_pointer<boost::mpl::_>,
            T2=int
        ]


 
j'ai l'impression qu'il arrive pas a bien tout remplacer, surtout que tout doit a priori se faire en deux étapes :  
   - le remplacement des _1 par les boost::add_pointer<_>
   - le remplacement du reste par les int...
Et je pense donc que c'est là que se trouve le problème, il peut pas faire tout en une passe. Et donc du coup, je vois pas trop comment faire une fonction lambda qui dans ses paramètres prend la métafonction avec laquelle elle doit travailler...
 
Si vous avez une idée :)

Reply

Marsh Posté le 13-09-2008 à 18:55:42   

Reply

Marsh Posté le 14-09-2008 à 11:15:19    

Tu effectue la beta-reduction de ta lambda trop tôt.
Ca devrait marcher :
 

Code :
  1. #include <boost/mpl/apply.hpp>
  2. #include <boost/type_traits/add_pointer.hpp>
  3. using namespace boost;
  4. using namespace boost::mpl;
  5. int main()
  6. {
  7.   // lambda expression for twice. lambda f x => f (f x)
  8.   typedef apply1< _1, apply1<_1,_2> > twice;
  9.   // Test with add_pointer and int
  10.   typedef mpl::apply2<twice,boost::add_pointer<mpl::_>,int>::type result;
  11.   // Validation
  12.   BOOST_MPL_ASSERT(( is_same<result,int**> ));
  13.   return 0;
  14. }


Reply

Marsh Posté le 14-09-2008 à 13:13:31    

Ok, merci de ton aide.
 
   Donc si je comprend bien, la première erreur était d'utiliser uniquement les mpl::apply qui laissent le compilo faire l'unification sur tous les placeholders d'un coup. Il fallait donc lors de la définition de twice, utiliser le apply1 pour spécifier qu'il doit d'abord faire l'unification sur la première variable en lui empêchant d'unifier la deuxième variable.  
 
   Par contre il y a un truc que je comprend toujours pas. Dans la définition de twice tu as utilisé le apply1 directement comme valeur qui va être utilisé par la métafonction:

Code :
  1. typedef apply1< _1, apply1<_1,_2> > twice;


Et pas la valeur de retour du apply1 comme on aurait fait dans une métafonction...

Code :
  1. typedef apply1< _1, typename apply1<_1,_2>::type > twice;


Je pense que je dois pas bien comprendre comment fonction le apply1, car je pensais que c'était juste le raccourcis d'écriture que j'avais vu dans la doc: (bon bien sur, il ne s'agissait pas le la véritable implémentation mais je pensais que cela était proche)

Code :
  1. template <class F, class X>
  2. template <class UnaryMetaFunctionClass, class Arg>
  3. struct apply1
  4.      : UnaryMetaFunctionClass::template apply<Arg>
  5. {};


Et donc, ça me paraissait logique de l'utiliser comme ça. Une petite explication (ou une indication où chercher dans la doc) ne serai pas de refus.  
 
merci :)

Message cité 1 fois
Message édité par Amonchakai le 14-09-2008 à 13:39:17
Reply

Marsh Posté le 14-09-2008 à 15:25:11    

Amonchakai a écrit :


Donc si je comprend bien, la première erreur était d'utiliser uniquement les mpl::apply qui laissent le compilo faire l'unification sur tous les placeholders d'un coup. Il fallait donc lors de la définition de twice, utiliser le apply1 pour spécifier qu'il doit d'abord faire l'unification sur la première variable en lui empêchant d'unifier la deuxième variable.


En gros oui. T'as jamais fait de LISP ou de ML en étant plus jeune car ca aide grandement dans ce cas :D
Ta fonction twice elle se type de la façon suivante :

Code :
  1. # let twice _1 _2 = _1 (_1 _2 );;
  2. val twice : ('a -> 'a) -> 'a -> 'a = <fun>
 

Mais comme apply n'est ni plus ni moins que la meta-fonction effetuant un appel de fonction, ca te donne de suite la bonne forme :

Code :
  1. # let apply1 _1 _2 = _1 _2;;
  2. val apply1 : ('a -> 'b) -> 'a -> 'b = <fun>
  3. # let twice _1 _2 = apply1 _1 ( apply1 _1 _2);;
  4. val twice : ('a -> 'a) -> 'a -> 'a = <fun>
 

En C++, on retrouve :

Code :
  1. apply1< _1, apply1<_1,_2> >
 
Amonchakai a écrit :


Par contre il y a un truc que je comprend toujours pas. Dans la définition de twice tu as utilisé le apply1 directement comme valeur qui va être utilisé par la métafonction:

Code :
  1. typedef apply1< _1, apply1<_1,_2> > twice;


Et pas la valeur de retour du apply1 comme on aurait fait dans une métafonction...

Code :
  1. typedef apply1< _1, typename apply1<_1,_2>::type > twice;



 

Au moment ou tu recupére le ::type d'une meta-fonction, tu déclenches son évaluation. Or apply _1 sur _2 sans remplacement ne veut rien dire.
Il faut conserver ton expression paresseuse jusqu'à la fin.

 
Amonchakai a écrit :


Je pense que je dois pas bien comprendre comment fonction le apply1, car je pensais que c'était juste le raccourcis d'écriture que j'avais vu dans la doc: (bon bien sur, il ne s'agissait pas le la véritable implémentation mais je pensais que cela était proche)

Code :
  1. template <class F, class X>
  2. template <class UnaryMetaFunctionClass, class Arg>
  3. struct apply1
  4.      : UnaryMetaFunctionClass::template apply<Arg>
  5. {};


Et donc, ça me paraissait logique de l'utiliser comme ça. Une petite explication (ou une indication où chercher dans la doc) ne serai pas de refus.


C'est bien ça. Mais la différence se trouve au niveau de la sémantique de la chose. Quand tu écris une meta-fonction avec de splaceholder, il faut arreter de voire des types C++ et raisonner en terme de fonction paresseuse.


Message édité par Joel F le 14-09-2008 à 15:28:39
Reply

Marsh Posté le 14-09-2008 à 18:25:31    

Ok, j'ai compris. merci beaucoup :)
 
(En ce qui concerne les langages fonctionnels, j'ai juste fait un peu de Caml l'année dernière. Ca aide déjà un peu dans la manière de procéder...)


Message édité par Amonchakai le 14-09-2008 à 18:26:20
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed