C++ 代码
class MyOwnString; // assume this implements a string class.
class HasMyOwnString // simple example that uses it
{
private:
MyOwnString m_name;
int m_age;
public:
HasMyOwnString( MyOwnString const& name, int age ) :
m_name( name ), m_age( age )
{
}
MyOwnString name() const
{
return m_name;
}
int age() const
{
return m_age;
}
};
class HasStdString
{
private:
std::string m_name;
int m_age;
public:
HasStdString( std::string const& name, int age ) :
m_name( name ), m_age( age )
{
}
std::string name() const
{
return m_name;
}
int age() const
{
return m_age;
}
};
BOOST_PYTHON_MODULE(test_cpp)
{
using namespace boost::python;
using boost::noncopyable;
class_<HasMyOwnString>( "HasMyOwnString", init<MyOwnString, int>() )
.def( "name", &HasMyOwnString::name )
.def( "age", &HasMyOwnString::age );
class_<HasStdString>( "HasStdString", init<std::string, int>() )
.def( "name", &HasStdString::name )
.def( "age", &HasStdString::age );
}
假设已包含所有相关标题。以上内容确实构建到了 python .pyd 中。
现在这是我想要使用的 Python:
myStdStringTest = test_cpp.HasStdString( "UsesStdString", 1 )
name = myStdStringTest.name()
age = myStdStringTest.age()
print( name, age, type(name) )
myOwnStringTest = test_cpp.HasMyOwnString( "UsesOwnString", 2 )
name = myOwnStringTest.name()
age = myOwnStringTest.age()
print( name, age, type(name) )
Python 工作的第一部分,即HasStdString。它知道如何自动将 Python str 输入转换为 std::string 以使绑定起作用。
第二部分未能预期 MyOwnString。
- MyOwnString 有一个来自 const char * 的隐式构造函数
- 我尝试了各种方法,加入了一些 boost 的重载,但找不到任何有效的方法。
我搜索了 boost 的代码,看看它们是如何让 str 自动转换为 std::string 的。operator.hpp 中的宏没有任何意义。builtin_converters.hpp 中的宏确实有意义,但它们似乎以其他方式进行所有转换(除了它们在我的 1.50.0 版本中存在编译器错误)并且没有解决问题。
本质上,我试图向 Python 公开的 API 有自己的字符串类。好吧,它已经够糟糕了,我无法改变它。但我希望 Python 用户不会注意到这一点,并且我希望等效的 Python API 在 C++ 代码中使用“自定义”字符串的任何地方都使用 Python 字符串。我想在一个地方定义转换,然后让它在我绑定函数的任何地方工作。
(为了那些想要 MyOwnString 实现的人,我在这里做了我自己的)
class MyOwnString
{
public:
MyOwnString()
: m_internal()
{
init();
}
MyOwnString( const char * val )
: m_internal()
{
init();
assign( val, strlen( val ) );
}
MyOwnString( MyOwnString const& other )
: m_internal()
{
init();
assign( other.c_str(), other.m_len );
}
MyOwnString( const char * val, size_t len )
: m_internal()
{
init();
assign( val, len );
}
~MyOwnString()
{
cleanup();
}
const char * c_str() const
{
return m_data;
}
size_t size() const
{
return m_len;
}
bool empty() const
{
return m_len == 0;
}
void clear()
{
cleanup();
m_internal[0] = '\0';
}
MyOwnString & operator=( MyOwnString const& other )
{
assign( other.c_str(), other.m_len );
return *this;
}
MyOwnString & operator=( const char * val )
{
assign( val, strlen(val) );
return *this;
}
private:
void init()
{
m_data = m_internal;
m_capacity = 0;
m_len = 0;
}
void cleanup()
{
if( m_data != m_internal )
{
delete [] m_data;
m_capacity = 0;
m_data = m_internal;
}
}
void assign( const char * text, size_t len ) // length not including null
{
if( len < EInternalSize ) // it fits into internal buffer
{
memcpy( m_internal, text, len );
m_internal[len]='\0';
cleanup(); // if we have dynamically allocated data remove it
m_len = len;
}
else if( m_capacity > len ) // fits into already assigned buffer
{
memcpy( m_data, text, len );
m_internal[len]='\0';
m_len = len;
}
else
{
// We need to allocate. Do that before we delete any existing buffer
char * buf = new char[ len + 1 ];
memcpy( buf, text, len );
buf[len] = '\0';
cleanup(); // if there was a buffer there remove it
m_data = buf;
m_capacity = len + 1;
m_len = len;
}
}
enum { EInternalSize = 16 };
size_t m_len;
size_t m_capacity;
char m_internal[EInternalSize];
char * m_data;
};
总结一下这个问题:
我需要在我的绑定中添加什么以允许 HasMyOwnString 的绑定按原样工作,同时提供的 Python 也可以工作......
(我不介意更改 HasMyOwnString 中的 init 部分,我希望任何其他不需要我提供参数类型的函数都可以工作)。