2016-03-27 7 views
1

C++ APIをラップしようとしていますが、私はchar*クラスメンバーのロードブロッキングを打っています。 boost-pythonはchar const *std::stringのタイプを(this answerに基づいて)pythonオブジェクトに自動的に変換しますが、それはchar*タイプのものです。これは私が(Pythonで)を取得エラーです:boost pythonはchar *データメンバーを自動変換しません。

TypeError: No to_python (by-value) converter found for C++ type: char* 

それは、文字列が変更されることはありませんので、これらの特定のchar *メンバーはおそらくchar const *として宣言されている必要があることが判明しました。

私はboost-pythonの新機能ですので、明白な答えがあるかもしれませんが、私はこの1つのグーグルでグーグルをしていません。

boost-pythonにこれらのメンバーを自動的に変換させる簡単な方法がありますか?char*のメンバー? (残念ながら私はラッピングは私の制御下にないよAPIので、char const *char *の宣言を変更することはできません。)

UPDATE

[OK]をので、私はカスタムを追加する必要があると思いますコンバータを使用してchar*のメンバーを処理します。私は1つ書く:

/** to-python convert for char* */ 
struct c_char_p_to_python_str 
{ 
    static PyObject* convert(char* s) { 
     return incref(object(const_cast<const char*>(s)).ptr()); 
    } 
}; 

// register the QString-to-python converter 
to_python_converter<char*, c_char_p_to_python_str>(); 

残念ながらこれは動作しません。これはエラーです:

私はテンプレート引数は、この署名を持っていることがわかります docsを見てみると
error: expected unqualified-id 
to_python_converter<char*, c_char_p_to_python_str>(); 
               ^

template <class T, class Conversion, bool convertion_has_get_pytype_member=false> 

char*は、私は、これは「didnの理由です推測しているクラスではありませんので、仕事。誰もがいくつかの洞察力を持っている?

アップデート2:

いいえ。 BOOST_PYTHON_MODULEコールの中で呼び出される必要があることがわかります。to_python_converter

私はto_python_converter(一部変更あり)を入手しました。私はフォームのpythonを変換する関数を書いてconverter::registry::push_backで登録しました。私はto_pythonコードが走っているのを見ることができますが、from_pythonコードは決して走っていないようです。

+0

(http://stackoverflow.com/questions/14029351/the-argument-of-char-converted -to-python-to-call-a-py-function-in-c-by-bo)を使用します。また、他の場所でboostを使用していない場合は、同じ関数を実装するより軽く、より最近の(C++ 11以降の)プロジェクトがあることを知っておいても大丈夫です(pybind11) https://github.com/pybind/pybind11)ここで、この「問題」は存在しないかもしれません。 – Silmathoron

+0

@ Silmathoron、pybind11は有望そうです。やってみます。 – Stephen

+0

型を適合させるゲッター関数とセッター関数でそれらを公開するのはどうですか?ゲッター/セッターは自立した関数であっても、クラスを変更する必要はありません。 –

答えて

1

サードパーティ製のAPIをラップして、それらのポインタを外部から露出させて酷使していることを脇に置いておきます。

は、ここでのコンセプトの短い証拠だ:exampletextを所有している

#include <boost/python.hpp> 
namespace bp = boost::python; 

class example 
{ 
public: 
    example() 
    { 
     text = new char[1]; 
     text[0] = '\0'; 
    } 

    ~example() 
    { 
     delete[] text; 
    } 

public: 
    char* text; 

}; 

char const* get_example_text(example* e) 
{ 
    return e->text; 
} 

void set_example_text(example* e, char const* new_text) 
{ 
    delete[] e->text; 

    size_t n(strlen(new_text)); 
    e->text = new char[n+1]; 
    strncpy(e->text, new_text, n); 
    e->text[n] = '\0'; 
} 

BOOST_PYTHON_MODULE(so02) 
{ 
    bp::class_<example>("example") 
     .add_property("text", &get_example_text, &set_example_text) 
     ; 
} 

クラス、およびメモリを管理する責任があります。

外部ゲッターとセッター機能を提供します。 getterはシンプルで、文字列への読み取りアクセスを提供するだけです。セッターは古い文字列を解放し、適切なサイズの新しいメモリを割り当て、データをコピーします。

>>> import so02 
>>> e = so02.example() 
>>> e.text 
'' 
>>> e.text = "foobar" 
>>> e.text 
'foobar' 

注:

  • set_example_text()おそらくstd::stringまたはbp::objectは、私たちはな長さを持っていることを容易に入手取り、潜在的に割り当てされる可能性があり

    ここでPythonインタプリタで簡単なテストです単に文字列以上のものから。

  • ラップするメンバー変数が多く、ゲッター/セッターパターンが似ている場合は、テンプレートを使用してコードを生成するか、ほんのわずかのマクロを使用してコードを生成します。
  • コンバータでこれを行う方法があるかもしれませんが、明日そのことを見ていきます。しかしここではメモリ管理を扱っているので、私は個人的にはこのように扱う方が好きです。何が起こっているのかがはっきりしているからです。
+0

概念の証明ありがとうございます。 – Stephen

1

これはDanの答えを広げます。ラムダ式を生成するマクロ定義を書きました。このアプローチの利点は、特定のタイプまたはメンバー名に結びついていないことです。

私はラッピングしていますが、私は数百のクラスをラップしています。これにより、すべてのchar*クラスメンバーに対して1回のマクロ呼び出しを行うことができます。ここで

はダンのサンプルコードの修正版である:[ `const`が必要とされている]どうやら

#include <boost/python.hpp> 
namespace bp = boost::python; 

#define ADD_PROPERTY(TYPE, ATTR) add_property(#ATTR, SET_CHAR_P(TYPE, ATTR), \ 
               GET_CHAR_P(TYPE, ATTR)) 

#define SET_CHAR_P(TYPE, ATTR) +[](const TYPE& e){     \ 
            if (!e.ATTR) return "";   \ 
            return (const char*)e.ATTR;  \ 
           } 
#define GET_CHAR_P(TYPE, ATTR) +[](TYPE& e, char const* new_text){ \ 
            delete[] e.ATTR;     \ 
            size_t n(strlen(new_text));  \ 
            e.ATTR = new char[n+1];   \ 
            strncpy(e.ATTR, new_text, n); \ 
            e.ATTR[n] = '\0';    \ 
           } 

class example 
{ 
public: 
    example() 
    { 
     text = new char[1]; 
     text[0] = '\0'; 
    } 

    ~example() 
    { 
     delete[] text; 
    } 

public: 
    char* text; 

}; 


BOOST_PYTHON_MODULE(topics) 
{ 
    bp::class_<example>("example") 
     .ADD_PROPERTY(example, text); 
} 
関連する問題