C++ 使用c++;11在boost::python';s add_属性(使用lambda获取_签名失败)

C++ 使用c++;11在boost::python';s add_属性(使用lambda获取_签名失败),c++,c++11,lambda,boost-python,C++,C++11,Lambda,Boost Python,我试图在boost::python的add\u属性中使用c++11 lambda作为访问函数,如下所示(本例中并不严格需要lambda,但对于lambda内部发生的更复杂的事情,例如验证,将需要lambda): 我尝试在std::function(…)中包装lambda,但这对参数推导没有帮助。有什么想法吗?使用该函数创建Python可调用对象。如果Boost.Python无法推断函数对象签名,那么必须将签名显式地作为一个函数提供。例如,lambda[](const A&A){return A.

我试图在
boost::python
add\u属性
中使用c++11 lambda作为访问函数,如下所示(本例中并不严格需要lambda,但对于lambda内部发生的更复杂的事情,例如验证,将需要lambda):

我尝试在
std::function(…)
中包装lambda,但这对参数推导没有帮助。有什么想法吗?

使用该函数创建Python可调用对象。如果Boost.Python无法推断函数对象签名,那么必须将签名显式地作为一个函数提供。例如,lambda
[](const A&A){return A.A;}
返回一个
int
并接受
const A&
,因此可以使用
boost::mpl::vector()
作为签名

下面是一个完整的示例,使用指向数据成员的指针,将非捕获lambda强制转换为函数,并使用lambda/functor:

#包括
结构A
{
A():A(2){};
INTA;
};
BOOST_PYTHON_模块(示例)
{
名称空间python=boost::python;
python::类_Ua(“A”)
//公开指向数据成员的指针。
.add_属性(“a1”、&A::A)
//将非捕获lambda强制转换为函数。
.add_属性(“a2”+[](常量A&A){return A.A;})
//从函子生成python函数。
.add_属性(“a3”,python::make_函数(
[](常量A&A){返回A.A;},
python::默认调用策略(),
boost::mpl::vector())
;
}
互动使用:

>>导入示例
>>>a=示例.a()
>>>断言(a.a1==2)
>>>断言(a.a2==2)
>>>断言(a.a3==2)

另一种基于文档化行为的非侵入性方法是将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);
  ;
}
#包括
结构A{
A():A(2){};
INTA;
};
int get__a(常数a&a)
{
//验证
//做更复杂的事情
返回a.a;
}
BOOST_PYTHON_模块(示例)
{
boost::python::class_uz(“A”)
.add_属性(“a”和get_a);
;
}

如果通过创建std::function使函数类型显式,那么使用下面的(C++11)代码就可以做到这一点

namespace boost {
  namespace python {
    namespace detail {

      template <class T, class... Args>
      inline boost::mpl::vector<T, Args...> 
        get_signature(std::function<T(Args...)>, void* = 0)
      {
        return boost::mpl::vector<T, Args...>();
      }

    }
  }
}
namespace boost{
名称空间python{
名称空间详细信息{
模板
内联boost::mpl::vector
get_签名(std::function,void*=0)
{
返回boost::mpl::vector();
}
}
}
}
例如:

boost::python::class_<A>("A")
    // .def_readonly("a",&A::a) // the classical way: works fine 
    // .add_property("a", [](const A& a){return a.a; }) // ideal way, not possible since compiler cannot deduce return / arguments types
    .add_property("a", std::function<int(const A&)>([](const A& a){return a.a; }))
    ;
boost::python::class_uz(“A”)
//.def_readonly(“a”,&a::a)//经典方法:很好用
//.add_属性(“a”,[](const a&a){return a.a;})//理想方式,不可能,因为编译器无法推断返回/参数类型
.add_属性(“a”,std::function([](常量a&a){return a.a;}))
;

两年后,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;})
                       ↑↑↑
  ;
}
BOOST\u PYTHON\u模块(BOOST\u PYTHON\u lambda)
{
boost::python::class_uz(“A”)
//.def_readonly(“a”,&a::a)//经典方法:很好用
.add_属性(“a”+[](常量a&a){return a.a;})
↑↑↑
;
}

您所需要的就是
+

我在尝试使用lambda时遇到了相同的问题,并且基于上述
std::function
的解决方案,我添加了更多的模板魔术,推导了lambda(或functor)的
操作符()
成员函数的类型:

然后,当包含此标题时,类似这样的事情就起作用了:

int *x = new int(0);
def("inc", [x] () { ++*x; });
def("get", [x] () { return *x; });
据我所知,ftm唯一需要注意的是,在包含
boost/python.hpp
(或者您正在使用的任何其他需要
get_签名
函数声明的boost.python头)之前,应该包含此头:

#包括“functor_signature.h”
#包括

是否尝试添加_属性(“a”,[](常量a&a){return a.a;})
?看起来
boost::python
无法识别函数签名。我猜
get_signature
只检查普通函数指针和成员函数指针,而不是函数对象的
operator()
。这可能不是首选解决方案,但您可能可以使用
+[](const A&A){return A.A;}
作为一种解决方法——或者如果这还不够,请与
make_函数
配合使用。lambda并不特别。我无法访问(403),但我看到Dave Abrams提出了一种方法,但我无法将其编译。您的建议实际上没有帮助,我的包装器是使用一堆宏生成的,它必须全部位于一个范围内。@eudoxos:要么添加Boost.Python的功能,要么在现有的限制范围内工作。绕过作用域的一种可能性是将lambda分配给全局函子,然后从非成员函数中调用该函子。更新问题以更紧密地匹配正在解决的问题可能会有所帮助,而不是将其保留为一个编译问题。这将深入了解有关自定义functor的更多详细信息。将尝试,非常好。应该建议将其包含在boost中。尝试您的代码,我无法使其工作。编译器(带有
--std=c++11
的clang和g++)说:
错误:没有匹配的函数用于调用“get_签名”
返回python::make_函数(f,default_call_policies(),detail::get_签名(f,(T*)0))
然后
注意:候选模板被忽略:无法将“RT(*)()与“std::function”匹配
等等。有什么提示吗?在Visual Studio中,它可以从VS2013和更高版本中工作。也许您的编译器不支持可变模板?您使用的是哪个版本
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;})
                       ↑↑↑
  ;
}
int *x = new int(0);
def("inc", [x] () { ++*x; });
def("get", [x] () { return *x; });
#include "functor_signature.h"
#include <boost/python.hpp>