如何使“自己的”C ++字符串类自动转换为绑定中的python字符串

时间:2012-12-24 14:37:12

标签: c++ python boost boost-python

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。

  1. MyOwnString有一个来自const char *
  2. 的隐式构造函数
  3. 我尝试了各种各样的东西,在一些boost的重载中挂钩,但找不到任何有用的东西。
  4. 我搜索了boost的代码,看看他们是如何自动转换为std :: string的str。 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部分,我希望其他任何不需要我提供参数类型的函数)。

1 个答案:

答案 0 :(得分:3)

答案在FAQ of Boost.Python中解答。

您需要实施并注册合适的custom_string_to_python_strcustom_string_from_python_str函数。