3

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 に自動的に変換する方法を知っています。

2 番目の部分は、MyOwnString を期待して失敗します。

  1. MyOwnString には、const char * からの暗黙のコンストラクターがあります。
  2. ブーストのオーバーロードのいくつかをフックして、さまざまなことを試しましたが、機能するものが見つかりません。

ブーストのコードを検索して、str を std::string に自動的に変換する方法を確認しました。operator.hpp のマクロはまったく意味がありません。builtin_converters.hpp のマクロは理にかなっていますが、(私のバージョン 1.50.0 でコンパイラ エラーが発生することを除いて) すべての変換を逆に行っているようで、問題を解決しませんでした。

基本的に、私が Python に公開しようとしている API には、独自の文字列クラスがあります。わかりました、それは十分に悪いです、私はそれを変更することはできません. しかし、私はこれが Python ユーザーに気づかれないようにしたいと思います。また、C++ コードで「カスタム」文字列が使用されている場合は、同等の Python API が Python 文字列を使用することを望みます。変換を 1 か所で定義し、それがどこでも機能するように、関数をバインドしたいと思います。

(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 部分を変更してもかまいません。パラメーターの型を指定する必要のない他の関数を動作させたいと思います)。

4

1 に答える 1

3

答えはBoost.Python の FAQ にあります

custom_string_to_python_str適切な関数と関数を実装して登録する必要がありcustom_string_from_python_strます。

于 2012-12-24T14:47:18.930 に答える