Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Boost::python Exposing C++ functions using and returning templates

I need to build python bindings for a C++ codebase. I use boost::python and I ran into problems trying to expose classes containing functions using and returning templates. 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.

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.

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.

>>> 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, i.e

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?

like image 309
LouisChiffre Avatar asked Jan 30 '11 18:01

LouisChiffre


1 Answers

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.

like image 93
Matthew Scouten Avatar answered Nov 04 '22 23:11

Matthew Scouten