我正在使用Boost Python库来包装我拥有的C ++类,以便我可以从Python调用它的方法。我的C ++类Clazz
有公共方法:
void doSomething(std::string& s) { ... }
void doSomethingWide(std::wstring& ws) { ... }
我创建了BOOST_PYTHON_MODULE
,指出了这两种方法。第一个使用std::string
我可以打电话的人。但是,当我尝试使用Python Unicode字符串调用第二个字符串时:
x = u'hello'
Clazz.doSomethingWide(x)
我收到错误:
ArgumentError: Python argument types in
Clazz.doSomethingWide(Clazz, unicode)
did not match C++ signature:
doSomething(Clazz, std::wstring)
我曾希望unicode
会自动与std::wstring
接口,就像常规Python字符串类型与std::string
一样。但是,情况似乎并非如此。
在另一个帖子中,有人建议先进行转换:
x = str(x.encode('utf-8'))
但是,我正在处理非常大的字符串,这会破坏我的代码的性能,因为{em> O(n)的字符数为x
。
我做能够修改我尝试与之交互的C ++库。有没有办法以我可以使用它的方式将Python unicode
类型传递到我的C ++库中?我已经远程搜索了互联网,并发现了一些转换器和其他内容的参考,但实现它们并没有解决上述错误信息(很可能我没有正确使用它们)。
答案 0 :(得分:2)
简而言之,类型转换通常会产生rvalue对象,因此参数必须通过值或const引用接受。因此,改变:
void doSomethingWide(std::wstring&);
以下任一项:
void doSomethingWide(std::wstring);
void doSomethingWide(const std::wstring&);
Boost.Python在2003年9月11日增加了std::wstring
conversions。作为一般规则,当在Boost.Python中发生类型转换时,结果对象将被视为右值。 boost::python::extract
观察者规范中间接注明了这种行为:
将存储的指针转换为
result_type
,T
或T const&
。
如果支持左值转换,则可能会为某些类型引入尴尬的语义。例如,C ++函数可以修改不可变的Python字符串。
这是一个完整的最小例子:
#include <iostream>
#include <string>
#include <boost/python.hpp>
class spam
{
public:
void doSomething(const std::string& str)
{
std::cout << "spam::doSomething(): " << str << std::endl;
}
void doSomethingWide(const std::wstring& str)
{
std::wcout << "spam::doSomethingWide(): " << str << std::endl;
}
};
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
python::class_<spam>("Spam")
.def("doSomething", &spam::doSomething)
.def("doSomethingWide", &spam::doSomethingWide)
;
}
交互式使用:
>>> import example
>>> spam = example.Spam()
>>> spam.doSomething("test")
spam::doSomething(): test
>>> spam.doSomethingWide(u"test")
spam::doSomethingWide(): test