9

我需要为 C++ 代码库构建 python 绑定。我使用 boost::python 并且在尝试公开包含使用和返回模板的函数的类时遇到了问题。这是一个典型的例子

class Foo 
{ 
    public: 
        Foo(); 
        template<typename T> Foo& setValue(
            const string& propertyName, const T& value); 
        template<typename T> const T& getValue(
            const string& propertyName); 
}; 

典型的 T 是字符串、双精度、向量。

阅读文档后,我尝试对使用的每种类型使用瘦包装器。这是字符串和双精度的包装器以及相应的类声明。

Foo & (Foo::*setValueDouble)(const std::string&,const double &) = 
    &Foo::setValue; 
const double & (Foo::*getValueDouble)(const std::string&) = 
    &Foo::getValue;

Foo & (Foo::*setValueString)(const std::string&,const std::string &) = 
    &Foo::setValue; 
const std::string & (Foo::*getValueString)(const std::string&) = 
    &Foo::getValue;

class_<Foo>("Foo") 
    .def("setValue",setValueDouble, 
        return_value_policy<reference_existing_object>()) 
    .def("getValue",getValueDouble,
        return_value_policy<copy_const_reference>()) 
    .def("getValue",getValueString, 
        return_value_policy<copy_const_reference>()) 
    .def("setValue",setValueString, 
        return_value_policy<reference_existing_object>());

它可以编译,但是当我尝试使用 python 绑定时,我得到了一个 C++ 异常。

>>> f = Foo()  
>>> f.setValue("key",1.0) 
>>> f.getValue("key") 
Traceback (most recent call last): 
  File "<stdin>", line 1, in ? 
  RuntimeError: unidentifiable C++ exception

有趣的是,当我只为双精度或字符串值公开 Foo 时,即

class_<Foo>("Foo") 
    .def("getValue",getValueString, 
        return_value_policy<copy_const_reference>()) 
    .def("setValue",setValueString, 
        return_value_policy<reference_existing_object>());

它工作正常。我错过了什么吗?

4

3 回答 3

3

这可能与您的问题没有直接关系,但我不相信使用这样的模板进行函数签名转换。我会这样包装它:

class_<Foo>("Foo") 
    .def("setValue", &Foo::setValue<double>, 
        return_value_policy<reference_existing_object>()) 
    .def("getValue", &Foo::getValue<double>,
        return_value_policy<copy_const_reference>()) 
    .def("getValue", &Foo::getValue<std::string>, 
        return_value_policy<copy_const_reference>()) 
    .def("setValue", &Foo::setValue<std::string>, 
        return_value_policy<reference_existing_object>());

如果这不起作用,您可能需要创建一些 shim 函数:

Foo& setValueDouble(foo& self, const string& propertyName, const double value)
{ 
    return self.setValue(propertyName, value)
}
...

并将它们导出为认为它们是成员函数。

在 Boost::Python 中将多个函数重载导出为同名是完全有效的做法,所以我认为这不是问题所在。

于 2011-01-31T16:33:12.547 回答
0

我怀疑问题是 boost::python 不知道要调用哪个重载来调用“getValue”——它应该调用 getValueDouble 还是 getValueString?如果您将它们显式绑定为 getValueString 和 getValueDouble (作为方法名称),我敢打赌它会起作用。

于 2011-01-30T19:01:13.670 回答
0

为返回/获取 boost::python::object 的 getter/setter 创建 C++ 包装器怎么样?然后,您可以简单地确定您在 C++ 包装器中获得的类型,并将其包装/解包到/从 boost::python::object 中。

struct FooWrap : public Foo
{
    using boost::python;
    Foo& setValueO(const string& propertyName, const object& obj)
    {
        object value;
        if(PyInt_Check(obj.ptr())) {
            return setValue<int>(propertyName, extract<int>(obj);
        } else if(PyFloat_Check(obj.ptr())) {
            return setValue<double>(propertyName, extract<double>(obj);
        } else if(PyString_Check(obj.ptr())) {
            return setValue<std::string>(propertyName, extract<std::string>(obj);
        }
        // etc...
    }

    object getValueO(const std::string& propertyName)
    {
        if(determineType() == TYPE_INT) { // however you determine the type
            return object(getValue<int>(propertyName));
        } else if(determineType() == TYPE_DOUBLE)   {
            return object(getValue<double>(propertyName));
        } else if(determineType() == TYPE_STRING)   {
            return object(getValue<std::string>(propertyName));
        }
        // etc...
    }
};

class_<Foo>("Foo") 
    .def("setValue", &FooWrap::setValueO, 
        return_value_policy<reference_existing_object>()) 
    .def("getValue", &FooWrap::getValueO,
        return_value_policy<copy_const_reference>()) 
于 2011-02-28T05:16:17.187 回答