Problèmes d’adaptation des fonctions membres dans Phoenix

J’utilise BOOST_PHOENIX_ADAPT_FUNCTION tout le temps dans Spirit. J’aimerais pouvoir adapter les fonctions des membres pour la même raison. Cependant, je reçois des erreurs de compilation si je fais quelque chose comme ceci:

 struct A { int foo(int i) { return 5*i; }}; BOOST_PHOENIX_ADAPT_FUNCTION(int, AFoo, &A::foo, 2) 

Existe-t-il un moyen simple d’adapter une fonction membre? Notez que je ne peux pas simplement stocker une expression de liaison dans une auto car je suis sur VC2008. Comment se fait-il que cela ne fonctionne pas comme dans bind et function ?

Merci,

Mike

La BOOST_PHOENIX_ADAPT_FUNCTION(RETURN,LAZY_NAME,FUNC,N) est vraiment simple. Il crée simplement un foncteur avec un operator() basé sur un modèle operator() qui retourne RETURN et a N parameters de template. Dans son corps, il invoque simplement FUNC(PARAMETERS...) . Mais &A::foo n’est pas directement appelable et votre erreur se produit. Vous pouvez utiliser:

 BOOST_PHOENIX_ADAPT_FUNCTION(int,AFoo,boost::mem_fn(&A::foo),2) 

Courir sur Coliru

 #include  #include  #include  #include  struct A { A(int f) : f_(f) {} int foo(int i) { return f_*i; } private: int f_; }; BOOST_PHOENIX_ADAPT_FUNCTION(int,AFoo,boost::mem_fn(&A::foo),2) int main() { using namespace boost::phoenix; using namespace boost::phoenix::arg_names; A instance(5); std::cout << AFoo(arg1,arg2)(&instance, 2) << std::endl; } 

En commençant par le plus simple:

Comment se fait-il que cela ne fonctionne pas comme dans bind et function?

Parce que la macro est conçue pour des fonctions, pas des fonctions membres. Les fonctions pointeur vers membre sont très différentes des pointeurs de fonction, c’est donc la fin de la route.


Dans votre exemple, A::foo n’a pas besoin d’être une méthode d’instance (fonction membre non statique), il suffit donc d’append static (et un paramètre implicite) et de le faire:

 struct A { static int foo(int i) { return 5*i; } }; BOOST_PHOENIX_ADAPT_FUNCTION(int, AFoo, A::foo, 1) 

Supposons cependant que vous souhaitiez avoir la fonction de membre non statique. Pour cette raison, ajoutons un petit état au type A :

 struct A { A(int f) : f_(f) {} int foo(int i) { return f_*i; } private: int f_; }; 

Phoenix propose les approches suivantes pour créer des acteurs paresseux appelant des fonctions membres:

  1. utilisez l’opérateur ->* . Cela conduit à une syntaxe légèrement obscure:

     A instance(9); int direct = (arg1->*&A::foo)(arg2) (&instance, 7); // direct == 63 
  2. alternativement, vous pouvez utiliser une expression bind (note: boost::phoenix::bind here!), ce qui pourrait bien être ce que vous cherchiez:

     int with_bind = bind(&A::foo, arg1, arg2) (&instance, 7); 

Maintenant, bien sûr, vous voudrez peut-être affecter le foncteur paresseux à une variable. À cet égard, je ne peux que recommander BOOST_AUTO :

 BOOST_AUTO(afoo, (arg1->*&A::foo)(arg2)); return afoo(&instance, 2); 

Ce qui fonctionne comme un charme.

Échantillon complet C ++ 03

Voir en direct sur Coliru

 struct A { A(int f) : f_(f) {} int foo(int i) { return f_*i; } private: int f_; }; #include  #include  #include  int main() { using namespace boost::phoenix; using namespace boost::phoenix::arg_names; A instance(9); int direct = (arg1->*&A::foo)(arg2) (&instance, 7); int with_bind = bind(&A::foo, arg1, arg2) (&instance, 7); assert(direct == with_bind); BOOST_AUTO(afoo, (arg1->*&A::foo)(arg2)); return afoo(&instance, 2); }