2011-03-31 55 views
4

我有一个C++类,通过使用boost::range提供函数返回范围来公开集合。使boost :: python :: range接受... boost ::范围

为了这个类导出到蟒蛇与boost::python,我使用功能boost::python::range,它可以接受两个参数:类返回集合的开始和结束迭代器的成员函数。

我想避免为每个集合手动编写开始/结束对,因为我已经提供了范围。但我不能设法写一个包装在boost :: python :: range接受作为参数返回一个范围的成员函数。有任何想法吗? (我实际上有超过一个类,这是模板化的,所以模板函数作为模板参数的模板类的成员函数的地址将不起作用,我的编译器说)

我会接受一个C++ 0x解决方案,如果编译与g ++ - 4.6。

编辑: 说我有这个类:如问一个示例代码

struct A 
{ 
    std::vector<int> c; 
    typedef boost::sub_range<std::vector<int> > c_range; 
    c_range getc() { return c; } 
}; 

以从getc方法Python的迭代器,我现在这两个成员函数添加到A类:

c_range::iterator c_begin() { return getc().begin(); } 
c_range::iterator c_end() { return getc().end(); } 

,然后将它们公开这样的:

boost::python::class_<A>("A") 
    .def("getc", boost::python::range(&A::c_begin, &A::c_end)); 

有没有直接写类似的方式:

.def("getc", pyrange(&A::getc)); 

并避免写c_beginc_end

+0

您可以显示代码形式的例子吗? – 2011-03-31 18:01:44

回答

4

解决方法是使用带有四个模板参数的更一般形式range:将开始/结束访问器创建为boost::bind'ed对象,然后指定目标模板参数range。对于常量迭代器,该代码满足我的需求:

namespace py = boost::python 
template <class T, class Return> 
struct range_accessor { 
    typedef Return (T::*RA)() const; 
    static typename Return::const_iterator 
    begin(RA ra, const T& t) { 
     return (t.*ra)().begin(); 
    } 
    static typename Return::const_iterator 
    end(RA ra, const T& t) { 
     return (t.*ra)().end(); 
    } 

    static py::object 
    pyrange(RA ra) { 
     auto b = boost::bind(&range_accessor::begin, ra, _1); 
     auto e = boost::bind(&range_accessor::end, ra, _1); 
     return py::range< 
      boost::python::objects::default_iterator_call_policies, 
      T> // the "Target" parameter, which can 
      // not be deduced from a bind object 
     (b,e); 
    } 
}; 

template <class T, class Return> 
py::object pyrange(Return (T::*ra)() const) { 
    return range_accessor<T, Return>::pyrange(ra); 
} 

编辑:稍微紧凑的解决方案,通过使用内部函数定义的局部结构:

template <class T, class Return> 
py::object 
pyrange(Return (T::*ra)() const) { 
    typedef Return (T::*RA)() const; 
    struct accessor { 
     static typename Return::const_iterator 
     begin(RA ra, const T& t) { 
      return (t.*ra)().begin(); 
     } 
     static typename Return::const_iterator 
     end(RA ra, const T& t) { 
      return (t.*ra)().end(); 
     } 
    }; 
    return py::range<boost::python::objects::default_iterator_call_policies, T> 
     (boost::bind(&accessor::begin, ra, _1), 
     boost::bind(&accessor::end, ra, _1)); 
} 
+0

啊,一直在寻找这样的代码示例..有点迟了,但请你能告诉我们你是如何在'.def'方法中暴露给Python的?我刚才问了一个非常类似的问题[这里](http://stackoverflow.com/questions/15659610/how-to-expose-c-classes-with-const-iterator?noredirect=1#comment22225235_15659610) – 2013-03-27 13:53:32