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

时间:2013-10-16 01:02:03

标签: c++ python boost boost-python

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

是否可以添加某种自动获得此功能的输入类型转换器?我知道我可以添加trampoline函数并自己进行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 *不起作用。

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

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

3 个答案:

答案 0 :(得分:3)

据我所知,无法从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

答案 1 :(得分:1)

我没有使用过Boost Python,但Python 2中的wchar_t是一个Unicode字符串,所以请尝试:

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

答案 2 :(得分:1)

这是我最终使用的:

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 ++端更好地清理输入字符串。

感谢所有的答案,你引导我朝着正确的方向前进,但我不得不调整一些事情,以便找到解决我确切用例的方法。