在boost :: python的add_property中使用c ++ 11 lambda作为访问器函数(get_signature在lambda中失败)

eud*_*xos 7 c++ lambda boost-python c++11

我想用C++ 11 lambda表达式作为访问功能boost::pythonadd_property,沿着下面的内容(拉姆达并不是必需在这个例子中,但将需要更复杂的东西拉姆达内部发生,如验证):

#include<boost/python.hpp>

struct A{
  A(): a(2){};
  int a;
};

BOOST_PYTHON_MODULE(boost_python_lambda)
{
  boost::python::class_<A>("A")
    // .def_readonly("a",&A::a) // the classical way: works fine 
    .add_property("a",[](const A& a){return a.a;})
  ;
}
Run Code Online (Sandbox Code Playgroud)

但是,使用clang ++(版本3.2)编译和-std=c++11(结果与g ++ 4.7相同),我收到此错误:

/usr/include/boost/python/class.hpp:442:66: error: no matching function for call to 'get_signature'
        return python::make_function(f, default_call_policies(), detail::get_signature(f, (T*)0));
                                                                 ^~~~~~~~~~~~~~~~~~~~~
/usr/include/boost/python/class.hpp:422:22: note: in instantiation of function template specialization 'boost::python::class_<A,
      boost::python::detail::not_specified, boost::python::detail::not_specified,
      boost::python::detail::not_specified>::make_fn_impl<A, <lambda at boost_python_lambda.cpp:12:21> >' requested here
        return this->make_fn_impl(
                     ^
/usr/include/boost/python/class.hpp:309:40: note: in instantiation of function template specialization 'boost::python::class_<A,
      boost::python::detail::not_specified, boost::python::detail::not_specified,
      boost::python::detail::not_specified>::make_getter<<lambda at boost_python_lambda.cpp:12:21> >' requested here
        base::add_property(name, this->make_getter(fget), docstr);
                                       ^
boost_python_lambda.cpp:12:4: note: in instantiation of function template specialization 'boost::python::class_<A,
      boost::python::detail::not_specified, boost::python::detail::not_specified,
      boost::python::detail::not_specified>::add_property<<lambda at boost_python_lambda.cpp:12:21> >' requested here
                .add_property("a",[](const A& a){return a.a;})
                 ^
Run Code Online (Sandbox Code Playgroud)

我尝试将lambda包装进去std::function<int(const A&)>(...),但这对参数演绎没有帮助.任何的想法?

Bar*_*rry 9

两年后跳进这里,Boost.Python确实不支持包装函数对象.但是你的lambda没有捕获任何东西.因此,它可以显式转换为函数指针:

BOOST_PYTHON_MODULE(boost_python_lambda)
{
  boost::python::class_<A>("A")
    // .def_readonly("a",&A::a) // the classical way: works fine 
    .add_property("a", +[](const A& a){return a.a;})
                       ???
  ;
}
Run Code Online (Sandbox Code Playgroud)

所有你需要的是+.


Tan*_*ury 5

使用该make_function()函数创建 Python 可调用对象。如果 Boost.Python 无法推导出函数对象签名,那么签名必须明确提供为MPL 前端可扩展序列。例如,lambda[](const A& a) { return a.a; }返回 anint并接受const A&,因此可以boost::mpl::vector<int, const A&>()用于签名。

这是一个完整的示例,演示了使用指向数据成员的指针、将非捕获 lambda 转换为函数以及使用 lambda/函子:

#include <boost/python.hpp>

struct A
{
  A(): a(2) {};
  int a;
};

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::class_<A>("A")
    // Expose pointer-to-data-member.
    .add_property("a1", &A::a)
    // Cast non-capturing lambda to a function.
    .add_property("a2", +[](const A& a) { return a.a; })
    // Make a python function from a functor.
    .add_property("a3", python::make_function(
        [](const A& a) { return a.a; },
        python::default_call_policies(),
        boost::mpl::vector<int, const A&>()))
    ;
}
Run Code Online (Sandbox Code Playgroud)

互动使用:

>>> import example
>>> a = example.A()
>>> assert(a.a1 == 2)
>>> assert(a.a2 == 2)
>>> assert(a.a3 == 2)
Run Code Online (Sandbox Code Playgroud)

另一种基于记录行为的非侵入式方法是将 lambda 编写为非成员函数,然后将其作为fget参数公开。虽然不像 lambda 那样简洁,但它仍然允许在访问成员变量时进行其他功能,例如验证。

#include <boost/python.hpp>

struct A{
  A(): a(2){};
  int a;
};

int get_a(const A& a)
{
  // do validation
  // do more complicated things
  return a.a;
}

BOOST_PYTHON_MODULE(example)
{
  boost::python::class_<A>("A")
    .add_property("a", &get_a);
  ;
}
Run Code Online (Sandbox Code Playgroud)