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

Exporting const wchar_t* c++ function with Boost Python

本文关键字:c++ 函数 wchar Boost Python 导出 const 使用      更新时间:2023-10-16

我正在尝试公开一个 c++ 函数,该函数将 const wchar_t* 作为 python 中的参数。在我看来,const wchar_t* 不是一种受支持的输入类型,它会自动公开为 python 字符串,然后像普通的 const char* 一样自动转换。

是否可以添加某种自动正确的输入类型转换器?我知道我可以添加蹦床函数并自己进行 unicode 转换,但让它自动运行会方便得多。

我的提升版本是 1.52,我正在 64 位窗口上使用 python 2.7。

下面是显示该问题的简单 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);
}

在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)
>>>

出于某种原因,此处的字符串方法 http://www.boost.org/doc/libs/1_52_0/libs/python/doc/v2/faq.html#custom_string 不适用于原始wchar_t*。

编辑:添加了缺少的包含和平台信息。

编辑:在提升文档中添加了有关示例的说明

据我所知,没有办法从 Python 窄字符串 ( str ) 自动转换为 const wchar_t* .

当 Boost.Python 尝试从 Python 对象转换时,它会在堆栈上分配内存以保存目标类型,然后尝试查找为目标类型注册的转换器。 在这种情况下,目标类型将为 const wchar_t* 。 一旦转换器指示PyObject是有效的转换候选项,就会进行转换,初始化堆栈分配内存中的目标类型。 由于 Python/C API 仅支持在编码时创建新PyObject,内存管理成为一个问题,因为 Boost.Python 只为wchar_t*分配内存。

由于 Boost.Python 不提供在使用转换后的值后调用的后钩子,因此一个简单的折衷方案可能是将const wchar_t*的参数类型更改为 std::wstring 。 当std::wstring管理自己的内存时,Boost.Python 可以将PyObject宽的字符串复制到其中。 此外,必要时,Boost.Python 会在转换为 std::wstring 的过程中将窄字符串编码为宽字符串。

示例代码:

#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);
}

用法:

>>> 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')

这是我最终使用的:

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;
}

然后将其作为转换器添加到:

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

只要输入参数是 unicode 类型而不是普通字符串类型,这就可以工作。对于我的初始示例,它将给出以下结果:

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

就我而言,C++ API 比 python 更严格,这意味着我在那里清理输入字符串比在C++端要好得多。

感谢您的所有回答,您引导我朝着正确的方向前进,但我必须稍微调整一下才能解决我的确切用例。