如何包装按类型重载函数? [英] How to wrap functions overloaded by type?

查看:214
本文介绍了如何包装按类型重载函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设有一个类 MYARRAY 它实现了 SOMETYPE 的数组。它是使用boost ::蟒蛇用C ++编写,并包装成Python的。

Suppose there is a class MyArray which implements an array of SomeType. It is written in C++ and wrapped into Python using boost::python.

BOOST_PYTHON_MODULE(my_array_module)
{
    class_<MyArray>("MyArray")
    // a few '.def's ...
    .def("__getitem__", ???)
    ;
}

在Python中的 __的GetItem __ 函数或者可以采取一个指标,并返回 SOMETYPE 值,或者分得一杯羹对象,返回片。

The __getitem__ function in Python can either take an index and return SomeType value, or take a slice object and return slice.

<一个href=\"http://stackoverflow.com/questions/7577410/boost-python-select-between-overloaded-methods\">There是如何处理在C重载函数++将它们包装成不同的Python功能。 是如何在Python重载函数,如果重载意味着不同数量的ARGS。

There is how to deal with functions overloaded in C++ to wrap them into different Python functions. There is how to make an overloaded function in Python, if overloading means different number of args.

但如何包装重载函数,如果他们通过arument类型不同?我需要2 的GetItem 函数在C ++中。

But how to wrap overloaded functions if they differ by arument types? I need 2 getitem functions in C++.

const SomeType& getitem(PyObject *self, size_t pos) {
    // ...
}

MyArray getitem(PyObject *self, slice sl) {
    // ...
}

如果您尝试使用 BOOST_PYTHON_FUNCTION_OVERLOADS 描述的方式来包装它的>,将无法编译。

If you try to wrap it using BOOST_PYTHON_FUNCTION_OVERLOADS way described here, it won't compile.

我可以做一个函数

PyObject* getitem(PyObject *self, PyObject *pos_or_slice) {
    extract<size_t> get_pos(pos_or_slice);
    if (get_pos.check()) {
        // return a single item (SomeType)
    }
    else {
        // return a slice (MyArray)
    }
}

但我不知道如何正确地包装 MYARRAY 的PyObject * ,这样,这将是一致通过类生成的包装_

but I have no idea how to properly wrap MyArray into PyObject*, such that it would be consistent with the wrapping generated by class_.

推荐答案

总之,只要C ++函数具有不同的参数类型,则每个函数都可以公开为单独调用同一个Python函数为 DEF()。 Boost.Python的将根据类型转换处理调度。如果类型不明确的,那么人们常常需要创建和公开的辅助功能调度;根据检查的boost ::蟒蛇::对象论点,即手动处理。

In short, as long as the C++ functions have different parameter types, then each function can be exposed as the same Python function with separate calls to def(). Boost.Python will handle the dispatching based on type conversions. If the types are ambiguous, then one often needs to create and expose an auxiliary function that manually handles dispatching based on inspecting the boost::python::object arguments.

下面是一个完整的小例子证明访问一个样机计数要么通过索引或切片类的数据:

Here is a complete minimal example demonstrating accessing a mockup Counter class's data via either an index or a slice:

#include <vector>
#include <boost/range/algorithm.hpp>
#include <boost/range/irange.hpp>
#include <boost/python.hpp>
#include <boost/python/slice.hpp>

/// @brief Mockup class that creates a range from 0 to N.
struct counter
{
  counter(std::size_t n)
  {
    data.reserve(n);
    boost::copy(boost::irange(std::size_t(0), n), std::back_inserter(data));
  }

  std::vector<int> data;
};

/// @brief Handle index access for counter object.
int spam_getitem_index(const counter& self, int index)
{
  // Attempt to convert to positive index.
  if (index < 0)
  {
    index += self.data.size();
  }

  // Check for valid range.
  if (index < 0 || self.data.size() <= index)
  {
      throw std::out_of_range("counter index out of range");
  }

  return self.data[index];
}

/// @brief Handle slicing for counter object.
boost::python::list spam_getitem_slice(
  const counter& self,
  boost::python::slice slice)
{
  namespace python = boost::python;
  python::list result;

  // Boost.Python will throw std::invalid_argument if the range would be
  // empty.
  python::slice::range<std::vector<int>::const_iterator> range;
  try
  {
    range = slice.get_indices(self.data.begin(), self.data.end());
  }
  catch (std::invalid_argument)
  {
    return result;
  }

  // Iterate over fully-closed range.
  for (; range.start != range.stop; std::advance(range.start, range.step))
  {
    result.append(*range.start);
  }
  result.append(*range.start); // Handle last item.
  return result;
}

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::class_<counter>("Counter", python::init<int>())
    .def("__getitem__", &spam_getitem_slice)
    .def("__getitem__", &spam_getitem_index)
    ;
}

交互式用法:

>>> from example import Counter
>>> counter = Counter(5)
>>> assert(counter[:]    == [0,1,2,3,4])
>>> assert(counter[:-2]  == [0,1,2])
>>> assert(counter[-2:]  == [3,4])
>>> assert(counter[::2]  == [0,2,4])
>>> assert(counter[1::2] == [1,3])
>>> assert(counter[100:] == [])
>>> assert(counter[1]    == 1)
>>> assert(counter[-1]   == 4)
>>> counter[100]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: counter index out of range
>>> counter[-100]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: counter index out of range

请注意如何当 spam_getitem_index()抛出一个的std :: out_of_range 例外,Boost.Python的把它翻译相关 IndexError Python异常。

Note how when spam_getitem_index() throws a std::out_of_range exception, Boost.Python translates it the associated IndexError Python exception.

这篇关于如何包装按类型重载函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆