如何使用boost :: python将模板化的类作为一个类暴露给python

时间:2016-09-12 14:44:41

标签: python c++ templates boost boost-python

在很多关于boost :: python的例子中,你会看到类似的东西:

using namespace boost::python;
typedef class_<std::vector<float>> VectorFloat;

当然,如果你需要一个double向量,你将会有一个名为DoubleVector左右的第二个类。 在我看来,这不是非常“pythonic”。如果C ++中的一个(模板化)类实际上是python中的一个类,它采用类似, ..., type='float', ... ,的参数,那将更直观(我认为)。这样,该类在pydocs中只出现一次,并且只需要向boost::python module添加一次。

因此,假设我们的C ++代码有一个简单的模板化类:

template <typename T>
MyClass
{
    T val;

public:
    MyClass(const T& tVal) : val(tVal) {}

    T    getVal()              { return val; }
    void setVal(const T& tVal) { val = tVal; }
};

现在我们要为Python编写一个接口。我的想法到目前为止:

使用boost :: variant

typedef boost::variant<MyClass<float>, MyClass<double>> VariantClass;    

class MyPythonClass
{
    VariantClass vClass;

public:
    MyPythonClass(
        const PyObject& tVal, 
        const boost::python::str& type)
    {
        using namespace boost::python;
        std::string type_string = extract<std::string>(type);

        if( type_string == "float" )
        {
            float f = extract<float>(tVal);
            vClass = MyClass(f);
        }
        else if( type_string == "double" )
        {
            double d = extract<double>(tVal);
            vClass = MyClass(d);
        }
    }

    boost::python::PyObject* getVal()
    {
        // What to put here?
    }

    void setVal(const boost::python::PyObject& tVal)
    {
        //What to put here?
    }
};

BOOST_PYTHON_MODULE(my_module)
{
    class_<MyPythonClass>("MyClass", init<boost::python::PyObject, int, boost::python::str>).def("getVal", &MyClass::getVal());
}

这个解决方案的明显缺点是我猜boost :: variant可以使用与我的类几乎完全不同的类型,除了它们存储的数据类型。因此,可能抽取的信息超出必要的范围。

所以我想这个问题归结为示例中的两个空函数。然而,当然也会接受更清洁,更短或更少的“如果”链式答案。正如标题所说,它是关于模板化的类和boost :: python,而不一定是关于boost :: variant。

1 个答案:

答案 0 :(得分:1)

这里有几个混乱的来源。首先,在Python中,object已基本上是一个变体 - 一切都是object。在C ++中,类模板不是类型 - 它是创建类型的方法。因此,如果您想将MyClass<T>从C ++公开到Python,您应该只公开所有MyClass<T>s

我会编写一个执行绑定的函数模板:

template <class T>
void bind_MyClass(const char* name) {
    class_<MyClass<T>>(name, init<T const&>())
        .add_property("val", &MyClass<T>::getVal, &MyClass<T>::setVal);
        ;
}

然后只需称呼它:

bind_MyClass<float>("MyClassFloat");
bind_MyClass<double>("MyClassDouble");