简体   繁体   English

Boost :: python使用和返回模板公开C ++函数

[英]Boost::python Exposing C++ functions using and returning templates

I need to build python bindings for a C++ codebase. 我需要为C ++代码库构建python绑定。 I use boost::python and I ran into problems trying to expose classes containing functions using and returning templates. 我使用boost :: python并且在尝试使用和返回模板公开包含函数的类时遇到了问题。 Here is a typical example 这是一个典型的例子

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

Typical T are string, double, vector. 典型的T是字符串,双,矢量。

After reading the documentation , I tried using thin wrappers for every type used. 阅读完文档后 ,我尝试使用所有类型的薄包装器。 Here are the wrappers for string and double and the corresponding class declaration. 这是string和double的包装器以及相应的类声明。

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>());

It compiles ok but when I try to use the python bindings, I get a C++ exception. 它编译好,但是当我尝试使用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

Interestingly, when I only expose Foo for double or string value, ie 有趣的是,当我只将Foo暴露给双倍或字符串值时,即

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

It works fine. 它工作正常。 Am I missing something? 我错过了什么吗?

This may not be related to your problem directly but I would not trust function signature casting with templates like that. 这可能与您的问题没有直接关系,但我不相信使用这样的模板进行函数签名转换。 I would have wrapped it like this: 我会像这样包裹它:

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>());

If that does not work, you may need to create some shim functions: 如果这不起作用,您可能需要创建一些填充函数:

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

and export those as thought they were member functions. 并将那些人视为他们的成员职能。

Exporting multiple function overloads to the same name is a perfectly valid thing to do in Boost::Python, so I do not think that that is the problem. 在Boost :: Python中导出多个函数重载到同一个名称是完全有效的事情,所以我认为这不是问题所在。

I suspect the problem is that boost::python does not know which overload to call for "getValue" - should it call getValueDouble or getValueString? 我怀疑问题是boost :: python不知道调用“getValue”的重载 - 应该调用getValueDouble还是getValueString? If you bind them explicitly as getValueString and getValueDouble (as the method name) I bet it will work. 如果你明确地将它们绑定为getValueString和getValueDouble(作为方法名称),我敢打赌它会起作用。

What about creating a C++ wrappers for getters/setters that return/take a boost::python::object? 如何为返回/获取boost :: python :: object的getter / setter创建C ++包装器? You can then simply determine the type you got in your C++ wrapper and wrap/unwrap it into/from boost::python::object. 然后,您可以简单地确定您在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>()) 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM