简体   繁体   English

使用Boost Python导出const wchar_t * c ++函数

[英]Exporting const wchar_t* c++ function with Boost Python

I'm trying to expose a c++ function taking a const wchar_t* as a parameter in python. 我正在尝试公开一个将const wchar_t *作为python参数的c ++函数。 It seems to me that const wchar_t* is not a supported input type that is automatically exposed as a python string and then converted automatically like an ordinary const char*. 在我看来,const wchar_t *不是受支持的输入类型,它会自动显示为python字符串,然后像普通的const char *一样自动转换。

Is it possible to add some kind of input type converter that gets this right automatically? 是否可以添加某种输入类型转换器来自动解决此问题? I know I can add trampoline functions and do the unicode conversion myself but it would be much more convenient to get this to behave right automatically. 我知道我可以添加蹦床功能并自己进行unicode转换,但是使它自动正确运行会更加方便。

My boost version is 1.52 and I'm working with python 2.7 on 64bit windows. 我的增强版是1.52,我正在64位Windows上使用python 2.7。

Here is example code for a trivial c++ sequence showing the issue: 这是显示此问题的普通c ++序列的示例代码:

#include <boost/python.hpp>
#include <iostream>
using namespace boost::python;
void testWcharParam(const wchar_t* str) {
    std::wcout << str << std::endl;
}
void testCharParam(const char* str) {
    std::wcout << str << std::endl;
}
BOOST_PYTHON_MODULE(test)
{
    def("testWcharParam", testWcharParam);
    def("testCharParam", testCharParam);
}

When importing and running this in python I get the following result: 在python中导入并运行时,得到以下结果:

>>> import test
>>> test.testCharParam('test')
test
>>> test.testWcharParam('test')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
    test.testWcharParam(str)
did not match C++ signature:
    testWcharParam(wchar_t const * __ptr64)
>>>

For some reason the approach for strings here http://www.boost.org/doc/libs/1_52_0/libs/python/doc/v2/faq.html#custom_string doesn't work for raw wchar_t*. 由于某种原因,此处的字符串处理方法http://www.boost.org/doc/libs/1_52_0/libs/python/doc/v2/faq.html#custom_string对于原始wchar_t *不起作用。

EDIT: Added missing includes and platform information. 编辑:添加了缺少的包含和平台信息。

EDIT: Added note on the example in the boost documentation 编辑:在boost文档中的示例上添加了注释

As far as I know, there is no way to get automatic conversions from Python narrow strings ( str ) to const wchar_t* . 据我所知,没有办法将Python窄字符串( str )自动转换为const wchar_t*

When Boost.Python attempts to convert from Python objects, it allocates memory on the stack to hold the destination type, then attempts to locate converters registered for the destination type. 当Boost.Python尝试从Python对象转换时,它将在堆栈上分配内存以保存目标类型,然后尝试查找为该目标类型注册的转换器。 In this case, the destination type would be const wchar_t* . 在这种情况下,目标类型将为const wchar_t* Once a converter has indicated that the PyObject is a valid candidate for conversion, the conversion will occur, initializing the destination type in the stack-allocated memory. 一旦转换器指示PyObject是转换的有效候选者,转换将发生,并在堆栈分配的内存中初始化目标类型。 With the Python/C API only supporting creating a new PyObject when encoding, memory management becomes an issue, as Boost.Python only allocated memory for wchar_t* . 由于Python / C API仅支持在编码时创建新的PyObject ,因此内存管理成为一个问题,因为Boost.Python仅为wchar_t*分配了内存。

As Boost.Python does not provide a post-hook to be invoked after the converted value has been used, one simple compromise may be to change the parameter types of const wchar_t* to std::wstring . 由于Boost.Python不提供使用转换后的值的后挂接,因此一个简单的折衷办法可能是将const wchar_t*的参数类型更改为std::wstring As std::wstring manages its own memory, Boost.Python can copy the PyObject wide string into it. 由于std::wstring管理自己的内存,Boost.Python可以将PyObject宽字符串复制到其中。 Additionally, when necessary, Boost.Python will encode narrow strings to wide strings during the conversion to std::wstring . 另外,必要时,Boost.Python会在转换为std::wstring过程中将窄字符串编码为宽字符串。

Example code: 示例代码:

#include <iostream>
#include <boost/python.hpp>

void testWcharParam(std::wstring str) { std::wcout << str << std::endl; }
void testCharParam(const char* str)   { std::wcout << str << std::endl; }

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::def("testWcharParam", testWcharParam);
  python::def("testCharParam", testCharParam);
}

Usage: 用法:

>>> import example
>>> example.testCharParam('test 1')
test 1
>>> example.testWcharParam(u'test 2')
test 2
>>> example.testWcharParam('test 3')
test 3

我没有使用Boost Python,但是Python 2中的wchar_t是Unicode字符串,因此请尝试:

>>> test.testWcharParam(u'test')

This is what I ended up using: 我最终使用的是:

void* convert_to_wcstring(PyObject* obj)
{
    if(PyString_Check(obj)) {
        throw_error_already_set();
    } else if(PyUnicode_Check(obj)) {
        return PyUnicode_AsUnicode(obj);
    }
    throw_error_already_set();
    return 0;
}

Then adding it as a converter in: 然后将其添加为转换器:

BOOST_PYTHON_MODULE(test)
{
    converter::registry::insert(convert_to_wcstring, type_id<wchar_t>(),&converter::wrap_pytype<&PyString_Type>::get_pytype);
    ...
}

This works as long as the input parameter is of unicode type rather than an ordinary string type. 只要输入参数是unicode类型而不是普通字符串类型,此方法就起作用。 For my initial example it would give the following result: 对于我的第一个示例,它将给出以下结果:

# Works
test.testWcharParam(u'test')

# Doesn't work
test.testWcharParam('test')

In my case the C++ API is more rigid than the python one which means I'm in much better position to sanitize input strings there than on the C++ side. 就我而言,C ++ API比python更为严格,这意味着与C ++相比,我在这里清理输入字符串的位置要好得多。

Thanks for all answers, you led me in the right direction but I had to tweak things a bit in order to get something to solve my exact use case. 感谢您提供的所有答案,您使我朝着正确的方向发展,但是我不得不稍作调整,以便获得一些解决我的确切用例的方法。

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

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