Problems adapting member functions in Phoenix

若如初见. 提交于 2019-12-24 10:45:02

问题


I use BOOST_PHOENIX_ADAPT_FUNCTION all the time in Spirit. I'd like to be able to adapt member functions for all of the same reason. However, I get compile errors if I do something like this:

struct A { int foo(int i) { return 5*i; }};

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

Is there an easy way to adapt a member function? Note that I can't just store a bind expression in an auto because I am on VC2008. How come it doesn't just work like in bind and function?

Thanks,

Mike


回答1:


The BOOST_PHOENIX_ADAPT_FUNCTION(RETURN,LAZY_NAME,FUNC,N)is really simple. It just creates a functor with a templated operator() that returns RETURN and has N template parameters. In its body it simply invokes FUNC(PARAMETERS...). But &A::foo is not directly callable, and so your error occurs. You can use:

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

Running on Coliru

#include <iostream>
#include <boost/phoenix.hpp>
#include <boost/phoenix/function.hpp>
#include <boost/mem_fn.hpp>

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;
}



回答2:


Starting with the simplest:

How come it doesn't just work like in bind and function?

Because the macro is designed for functions, not member functions. Pointer-to-member-functions are very different from function pointers, so that's the end of the road.


In your example, A::foo doesn't actually need to be an instance method (non-static member function), so just add static (and an implicit parameter) and be done:

struct A {
    static int foo(int i) {
        return 5*i;
    }
};

BOOST_PHOENIX_ADAPT_FUNCTION(int, AFoo, A::foo, 1)

Let's assume, though, that you did want to have the non-static member function. For this reason, let's add a little state to the A type:

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

Phoenix provides the following approaches to create lazy actors calling member functions:

  1. use the ->* operator. This leads to slightly obscure syntax:

    A instance(9);
    
    int direct    = (arg1->*&A::foo)(arg2)
                        (&instance, 7); // direct == 63
    
  2. alternatively, you can use a bind expression (note: boost::phoenix::bind here!), which might just be what you were looking for:

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

Now, of course, you might be looking to assign the lazy functor to a variable. In that respect, I can only recommend BOOST_AUTO:

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

Which works like a charm.

Full C++03 Sample

See it Live on Coliru

struct A {
    A(int f) : f_(f) {}

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

#include <boost/phoenix.hpp>
#include <boost/phoenix/function.hpp>
#include <cassert>

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);
}


来源:https://stackoverflow.com/questions/25770420/problems-adapting-member-functions-in-phoenix

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!