【问题标题】:How to add a custom implicit conversion to a C++ type in Boost::Python?如何在 Boost::Python 中向 C++ 类型添加自定义隐式转换?
【发布时间】:2010-11-18 05:57:54
【问题描述】:

在我的 C++ 代码中,我有一个 Foo 类,其中包含许多将 Bar 类型变量作为参数的方法:

class Foo {
public:
  void do_this(Bar b);
  void do_that(Bar b);
  /* ... */
};

Bar 有许多构造函数,可以从许多常见类型(例如 int、std::string、float 等)创建新对象:

class Bar {
public:
  Bar(int i);
  Bar(float f);
  Bar(std::string s);
  /* ... */
};

我用 Boost::Python 包装了它,现在我可以使用 Python 文字直接调用我的 Foo 方法,因为它们被隐式转换为 Bar 对象。

f = Foo()
f.do_this(5)
f.do_that("hello")

现在,我还希望能够使用其他 Python 类型,例如元组,如下所示:

f.do_that((1,2,3))

但我不想触及原始的 Bar 定义,也不想用 Boost::Python 的东西污染我的 C++ 库。我想在我的绑定代码中编写一个包装函数,但我就是不明白这是否可行,以及这样做的正确方法是什么。

换句话说:我可以注册一个工厂函数以在 Python 中用作自动转换吗?

【问题讨论】:

    标签: c++ python boost-python


    【解决方案1】:

    包装代码附近的子类栏,并为您的子类提供一个接受 bp::object(或更具体的 python 类型)的 ctor

    struct Bar_wrapper:Bar,bp::wrapper<Bar>
    {
        Bar_wrapper(bp::object arg)
        {
            //code to build a Bar_wrapper Here
        }
    }
    

    然后将一个 Bar_wrapper 导出到 python 中而不是 Bar,并将其称为 Bar 作为 python 名称:

    class<Bar_wrapper>("Bar")
        ...
        .def(init<bp::object>())
        ...
    

    【讨论】:

    • 只是为了确保:然后您将在 Bar_wrapper 中添加接受其他 Python 类型的新重载,对吧?
    • bp::object 涵盖了所有内容,包括 int 和 str。首先将 .def 用于更具体的类型。除此之外,是的,用你喜欢的任何类型重载 ctor。
    【解决方案2】:

    添加一个新的构造函数template &lt;typename T&gt; Bar(T) 在您的标题中并实现为template <> Bar::Bar(Tupple) {}

    【讨论】:

    • UncleZeiv在问题中提到他不想修改Bar。目前尚不清楚您为什么要挑战这一点。
    【解决方案3】:

    创建某种类型的 TupleCollector 并重写“operator ,(int)”,以便您可以编写

    f.do_that((TuppleCollector(), 1, 2, 3))
    

    最后创建 TupleCollector 和预期目标之间的转换

    【讨论】:

    • 谢谢,这是一个有趣的想法,但不是我想要的……我想直接使用元组。我设法为接受元组的 Bar 创建了一个新的构造函数,但是没有进行隐式转换,我必须显式地编写 Bar((1,2,3)) 。 :|
    • 从 tuples 类派生并进行任何您想要的 int 分配。 (运算符,-也适用)
    【解决方案4】:

    您可以创建一个静态工厂方法,然后将其公开为该类的 Python 构造函数之一。只需制作一个可以接受任何 Python 对象的转换器,您就可以随心所欲地做任何事情。

    using namespace boost::python;
    
    Bar CreateBar(object obj)
    {
        // Do your thing here
    
        return Bar;
    }
    
    // ..................
    
    class_<Bar>("Bar")
        // .....................
        .def("__init__", make_constructor(&CreateBar))
        //.............
        ;
    

    【讨论】:

      【解决方案5】:

      您可以注册 from-python 转换器,它将从任意对象构造 Bar 实例。请参阅here 和我自己的示例(将(Vector3,Quaternion) 元组或7*双元组转换为3d 转换Se3here

      请注意,该逻辑有两个步骤,首先您确定对象是否可转换(convertible;在您的情况下,您检查它是否是一个序列,并且具有正确数量的元素),然后是construct方法被调用,它实际上返回实例,分配的指针作为参数传递。

      然后必须在BOOST_PYTHON_MODULE 中注册转换器。由于转换器注册表是全局的,一旦注册,它将在任何地方自动使用。所有Barconst Bar&amp; 类型的函数参数都应该处理得很好(我也不确定Bar&amp;)。

      【讨论】:

        【解决方案6】:

        你可以导出函数do_that,它接受boost::python::object参数,检查param是否为python元组,提取数据并将其传递给对象。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-05-21
          • 1970-01-01
          • 1970-01-01
          • 2012-01-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多