There are two approaches to this problem:
- Export the helper function as
Hello.storeFile , which takes boost::python::str , builds std::vector<unsigned char> from a string, and delegates C ++ member functions Hello::storeFile . - Write a custom converter. Although transducers cannot be registered based on each function, they are pretty well embraced by not performing any unintended conversions. This approach often provides more reusability.
Helper function
Using a helper function will not affect any other exported function. Thus, the conversion between the python string and std::vector<unsigned char> will only happen for Hello.storeFile .
void Hello_storeFile(Hello& self, boost::python::str str) { std::cout << "Hello_storeFile" << std::endl; // Obtain a handle to the string. const char* begin = PyString_AsString(str.ptr()); // Delegate to Hello::storeFile(). self.storeFile(std::vector<unsigned char>(begin, begin + len(str))); } ... BOOST_PYTHON_MODULE(hello) { namespace python = boost::python; python::class_<Hello>("Hello") // This method takes a string as parameter and print it .def("printChar", &Hello::printChar) // This method takes a vector<unsigned char> parameter .def("storeFile", &Hello_storeFile) ; }
Custom converter
Transmitter registration consists of three parts:
- A function that checks if
PyObject convertible. Returning NULL means PyObject cannot use the registered converter. - A build function that builds a C ++ type from
PyObject . This function is called only if converter(PyObject) does not return NULL . - The type of C ++ that will be created.
Therefore, for a given C ++ type, if converter(PyObject) returns a non- NULL , then construct(PyObject) will create a C ++ type. The C ++ type serves as a key in the registry, so Boost.Python should not perform unintended conversions.
In the context of the question, we need a converter for std::vector<unsigned char> , where converter(PyObject) returns not NULL if PyObject is PyString , and converter(PyObject) will use PyObject to create and populate std::vector<unsigned char> . This conversion will only happen if for exported C ++ functions that have the std::vector<unsigned char> (or constant reference) parameter and the argument provided from python is a string. Therefore, this custom converter will not affect exported functions with std::string parameters.
Here is a complete example. I decided to make a universal converter to allow the creation of several types from a python string. Thanks to the support of the chain, it should have the same feeling as other types of Boost.Python.
And an example of use:
>>> from hello import Hello >>> h = Hello() >>> h.printChar('abc') printChar: abc >>> h.storeFile('def') storeFile: 3: def >>> h.storeFile([c for c in 'def']) Traceback (most recent call last): File "<stdin>", line 1, in <module> Boost.Python.ArgumentError: Python argument types in Hello.storeFile(Hello, list) did not match C++ signature: storeFile(Hello {lvalue}, std::vector<unsigned char, std::allocator<unsigned char> >)
For more on custom C ++ converters and containers, consider this answer.