2012-02-16 5 views
0

StringIO変数を生成するPythonコードがいくつかあります。この変数をC++関数に渡すには、stringstreamパラメータを使用してください(C++のstringstreamはPythonのStringIOに最も近いものです)。 swigを使ってこの翻訳を行う簡単な方法はありますか?swypeを使ってPython StringIOをC++の文字列に渡す

swigモジュールには、いくつかのストリングストリームコードが含まれているstd_sstream.iがありますが、swigのマニュアルやWeb検索で使用している例はありません。

少し明確にするために、私は以下のいくつかの非常に単純なコードを取り上げます。 はここに固定されており、私は変更することはできませんれます。test.cppです:

#include <iostream> 
#include <sstream> 

#include "test.h" 

using namespace std; 

void StTest(stringstream &ss) 
{ 
    cout << ss << endl; 
} 

はここにも固定されているTEST.Hです:

#include <sstream> 

using namespace std; 

void StTest(stringstream &ss); 

ここに私が編集して呼び出すことができますPythonのコードがありますC++ StTest機能(私たちはこのtest_test.pyと呼ぶことにします):

#!/usr/bin/env python 

import StringIO 
import test 

ss = StringIO.StringIO() 
ss.write("Hello") 

# Maybe some thing here to convert ss from StringIO to stringstream 

test.StTest(ss) 

だから私は上記のコメント行ににstringstreamしたStringIOからの変換を行うことができる何かを探しています。これを使用するべきで何であるように私は、私がtest.iで「std_sstream.i」を含めました

/* test.i */ 
%module test 

%{ 
#include "test.h" 
%} 

%include "std_sstream.i" 
%include "test.h" 

ここSWIGのためtest.iファイルで私の最初の発掘は、そのものんです想定する。何かをさせるためにこのファイルに何かを追加する必要がありますか?

現在、エラーレポートtest_test.pyを実行する場合は、次のとおりです。

TypeError: in method 'StTest', argument 1 of type 'stringstream &' 

答えて

1

理由だけではなく、あなたが StringIO.getvalue()を呼び出してから取得され、文字列ではPyArg_ParseTupleを呼び出しませんか?

このような場合は、

const char* cstring; 
if (!PyArg_ParseTuple(args,"s", &cstring)) //Note the & 
     return NULL; 
std::string stdstring = cstring; 
std::stringstream buffer(stdstring); 

また、cStringIO hereのC APIも参照してください。

追加の要件の後、固定制約内でSWIGを使用して解決策を発見しようとしました。

最初の可能な解決策は、インライン展開ソリューション(文字列を取得して拡張をストリングストリームにしてStTestを呼び出すStTestを拡張)でしたが、提供されたサンプルにはメソッドが1つしかなく、クラスもないため、制約を満たす。

最終的なインターフェイスファイルは次のようになります。

/* test.i */ 
%module test 

%{ 
#include "test.h" 
#include <sstream> 
#include <iostream> 
%} 
using namespace std; 
%include "std_sstream.i" 
%include "test.h" 

%include <typemaps.i> 

%typemap(in) std::stringstream & (char *buf = 0, size_t size = 0, int alloc = 0, std::stringstream stream) 
{ 
    if (SWIG_AsCharPtrAndSize($input, &buf, &size, &alloc) != SWIG_OK) 
    { 
    %argument_fail(SWIG_TypeError, "(TYPEMAP, SIZE)", $symname, $argnum); 
    } 

    stream.write(buf, size - 1); 

    $1 = &stream; 
} 

SWIGは上記のインターフェイスファイルのtypemapを無視しましたが、その理由はわかりません。それはPythonでストリングストリームオブジェクトを作成することができましたが、オブジェクトのタイプがストリングストリーム&のタイプではなかったため、同じタイプのエラーが発生してStTestに渡されませんでした(マッピングされたswigタイプもstd_sstream.iによって生成された型と一致します。これはおそらく、参照型の型マップを含んでいないためです)。

次はSWIGのラッパーをオーバーライドすることを提案したアプローチの実装でした。結果としてラップされた関数は次のようになりました。文字列が正しくストリームラインのプリントに

SWIGINTERN PyObject *_wrap_StTest(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { 
    PyObject *resultobj = 0; 
    void *argp1 = 0 ; 
    int res1 = 0 ; 
    PyObject * obj0 = 0 ; 
    int argc; 
    PyObject *argv[3]; 
    int ii; 
    char *cstring; 
    std::stringstream testbuffer; 
    if (!PyTuple_Check(args)) SWIG_fail; 
    argc = args ? (int)PyObject_Length(args) : 0; 
    for (ii = 0; (ii < 2) && (ii < argc); ii++) { 
    argv[ii] = PyTuple_GET_ITEM(args,ii); 
    } 
    if (argc == 1) { 

    if (!PyArg_ParseTuple(args,"s",&cstring)) 
SWIG_fail; 
    std::string teststring = cstring; 
    testbuffer.str(cstring); 
    std::cout << "the string in the stream: " << testbuffer.str() << std::endl; 
    } 

    StTest(testbuffer); 
    resultobj = SWIG_Py_Void(); 
    return resultobj; 
fail: 
    return NULL; 
} 

(それは18000行以上の長さであるとして全体のラッパーファイルを含めることを行っていない)、しかしStTest関数ににstringstreamを渡すことにstringstreamのメモリ内の位置を表示します。これは、文字列ストリームが以下のStack Overflow Questionの受け入れられた答えのようにバインドされていないために予想されます。

私はStTest(testbuffer);をboostのバインドを使ったバージョンに置き換えることができ、それは必要に応じて動作しますが、検証できたと仮定します。便利だった

参考文献は、私は本当にC++コードで多くを行うことはできません

+0

を含め、それはPythonのコード私はmaに編集することができますこの仕事は、私はこの提案が私が後にしているものに合うとは思わない。 – user1215017

+0

元の質問にサンプルコードを追加してより明確にしました。 – user1215017

関連する問題