2017-02-24 7 views
0

コンテキストは埋め込まれたpythonスクリプトのもので、C++で書かれたコードからインタープリタ を呼び出しています。ラッパーからベクトルのマップへの抽出

C++とPythonの以下のコード二つの最も一般的なSTLコンテナ、C++でラップPythonで使用し、C++でバック抽出する手法を要約:

  • のstd ::ベクトル
  • STDを:: map

特に、std :: string型要素を保持する場合に焦点を当てています。

ブースト・イテレータと反復可能スイートは、両方の言語に共通する概念にマッピングされていますが、2つのプログラミング環境ではかなり異なって扱われています。

私は、既存の材料や個人実験をもとに、最も一般的な用途に意図された方法であると思われるものを明らかにしました。他の場所では表示されていないものはありませんが、boost :: pythonは例と説明のケースで冗長性を少しでも許しているように感じます。

これまで解決できないようなケースが1つあります。文字列のラップベクターをC++に戻すことです。誰かが私にこのことを教えてもらえると感謝しています。

このコードは自己完結型であり、2つの目的を果たします。まず、自分のように、シンプルなユースケースの例を探している人を助けるためのものです。また、doubleのベクトルの操作は、ベクトル文字列よりも簡単です。

以下のC++の例では、本質的に実行時エラーが発生します。 typedef std :: vector VecStr; class boost :: python :: class> struct boost :: python :: deltail :: not_specified_strucこのtypeMapStringVectorStringのPythonオブジェクトから。

ご迷惑をおかけして申し訳ございません。

PS:メモリから修正されたコードを再構築しなければならず、構文エラーが発生する可能性があります。私は接続されたマシンにアクセスするとすぐにそれらを修正します。

#include "stdafx.h" 
#include <boost/python.hpp> 
#include <boost/python/suite/indexing/vector_indexing_suite.hpp> 
#include <boost/python/suite/indexing/map_indexing_suite.hpp> 
#include <Python.h> 
#include <string> 
#include <iostream> 
#include <vector> 

using namespace std; 
using namespace boost::python; 

BOOST_PYTHON_MODULE(idctor) 
{ 
    typedef std::vector<string> VectorString; 
    typedef std::map<string, VectorString> MapVectorString; 
    typedef class_<VectorString, shared_ptr<VectorString>> pyVectorString; 
    using namespace boost::python; 
    class_<std::vector<double> >("DoubleVector") 
     .def(vector_indexing_suite<std::vector<double> >()); 

    class_<std::vector<std::string>,shared_ptr<VectorString> >("VectorString") 
     .def(vector_indexing_suite<std::vector<string> >()); 

    class_<std::map<std::string, double> >("StringDoubleMap") 
     .def(map_indexing_suite<std::map<std::string, double> >()); 

    class_<std::map<string, string> >("MapStringString") 
     .def(map_indexing_suite<std::map<std::string, string> >()); 

    class_<std::map<string, VectorString> , shared_ptr<MapVectorString>>("MapStringVectorString") 
     .def(map_indexing_suite<std::map<std::string, VectorString> >()); 
} 


typedef std::vector<string> VectorString; 
typedef class_<VectorString> pyVectorString; 
typedef class_<VectorString, shared_ptr<VectorString>> pyMapVectorString; 


int main() 
{ 
    PyImport_AppendInittab("idctor", &PyInit_idctor); 
    Py_Initialize(); 
    try { 

     //PyInit_hello(); 
     object main 
      = object(handle<>(borrowed(PyImport_AddModule("__main__")))); 
     object main_namespace = main.attr("__dict__"); 
     PyRun_SimpleString("import sys\n"); 
     exec_file("G:\\Developments\\VisualStudio\\BoostPythonSTLContainers\\stlcontainers.py", main_namespace); 
     //  Getting back an Python object containing a 
     //   vector of double, extracting the 
     //   corresponding typed C++ object and using it 
     object pyv = main_namespace["v"]; 
     //----------------> this works <-------------- 
     std::vector<double>& v = extract<vector<double>&>(pyv); 
     v.push_back(665); 
     //----------------> this does not <---------------- 
     //  Getting back a working Python object 
     object pyvs = main_namespace["vs"]; 
     // Attempting to convert it back to its true C++ type 
     // Here the conversion fails: 
     VectorString& vs = extract<VectorString&>(pyvs); 
     vs.push_back("not yet the beast"); 

     // Attempt to do the same with a map of string to vector of strings 
     object pymvs = main_namespace["mvs"]; 

     //----------------> Clearly this fails too <-------------- 
     pyMapVectorString& mvs = extract<pyMapVectorString&>(pymvs); 
     object pyvs = mvs["this "]; 
     VectorString& vs = extract<VectorString&>(pyvs); 
     vs.push_back({ "should ","work" }); 
    } 
    catch (error_already_set) { 
     PyErr_Print(); 
     return 1; 
    } 

    Py_Finalize(); 
    return 0; 
} 

、ここで(作業)のpythonのコードです:

# 
# All the python code below is working fine 
#   (the issue is converting back in C++) 
import idctor 
#defining a function to print a container 
def tostr(container): 
    string ='[' 
    for i in container: 
     string += str(i)+"," 
    string+='end]' 
    return string 

# Turning it into a instance method 
idctor.DoubleVector.__str__ = tostr 

# instantiating a vector of doubles 
v = idctor.DoubleVector() 
v.append(1.0) 
v.append(2.0) 
for i in v: 
    print(i) 

#instantiating a vector of strings 
idctor.VectorString.__str__ = tostr 
vs = idctor.VectorString() 
vs.append("he2") 
vs.append("he1") 
print("Directly: ", vs) 
for s in vs: 
    print(s) 
m = idctor.StringDoubleMap() 

# instantiating a map of string to doubles 
m["a"] = 1 
m["b"] = 2 
for i in m: 
    print(i) 
print(m) 

#instantiating a map of string to strings 
ms = idctor.MapStringString() 
ms["a"]="he1" 
ms["b"]="he2" 
for s in ms: 
    print(s) 

#instantiating a map of string to vectors of strings 
mvs = idctor.MapStringVectorString() 
mvs["a"]=vs 
vs2=idctor.VectorString() 
vs2.append("cy") 
vs2.append("ve") 
mvs["b"]=vs2 
for vs in mvs: 
    print(vs) 
+2

「冗長でかなり致命的なエラー」あなたはあなたの質問にそれを含めるべきです。 –

答えて

0

最初の問題は、クラスのテンプレート宣言でNoProxyディレクティブ= trueオプションを入力することによって補正することができます。 2番目の問題は解決されず、このケースを処理するためにはPythonの特別なコンバータを構築する必要があります。私はまだそれを行う方法を理解することです。しかし、私は、おそらく醜い回避策が、Pythonオブジェクト自体に依存していることを発見しました。一部の人がこの道をたどりたい場合に備えて追加されました。

BOOST_PYTHON_MODULE(idctor) 
{ 
typedef std : : vector <string> VectorString; 
typedef std::map<string, VectorString> MapVectorString; 
typedef class_<Vector String, shared_ptr<VectorString>> pyVectorString; 
using namespace boost::python; 

//     NOTICE THE TRUE IN THE 
//   vector_indexing_suite second template argument 
class_<std::vector <std::string>, Shared_ptr <VectorString> > ("VectorString") 
.def(vector_indexing_suite<std::vector<string>, true >()); 


class <std::map<std::string, double> > ("StringDoubleMap") 
.def(map_indexing_suite<std::map<std::string, double>, true >()); 

class <std::map<string, string> > ("MapStringString") 
.def(map indexing suite<std::map<string, string>, true >()); 

class <MapVectorString, shared ptrkMapVectorString>, boost::noncopyable>("MapStringVectorString") 
.def(map_indexing_suite<MapVectorString, true >()); 

} 

typedef std::vector<string> VectorString; 
typedef class_<VectorString> pyVectorString; 
typedef std::map<string, VectorString> MapVectorString; 
typedef class_<MapVectorString, shared_ptr<MapVectorString>> pyMapVectorString; 

int main() 
{ 

PyImport_AppendInittab ("idctor", &PyInit_idctor) ; 
Py_Initialize(); 
try { 
object main 
= object (handle<> (borrowed (Pylimport_AddModule ("__main__")))); 
object main_namespace = main.attr("__dict__"); 
exec_file ("WrappedSTLContainer.py", main_namespace); 

// Getting back a vector of double in C++ and using it 
object pyv = main_namespace ["v"]; 
//- - - - - - - - - - - - - - - - > this works <- - - - - - - - - - - - - - 
std::vector<double>& v = extract<vector<double>&>(pyv); 
v.push_back(665) ; 
// Getting back a vector of string in C++ and attempting to use it 
object pyvs = main namespace["vs"]; 
//- - - - - - - - - - - - - - - - > this works now <- - - - - - - - - - - - - - 
std::vector<std::string>& vs = extract<vector<string>&>(pyvs); 
vs.push_back("Almost the Beast"); 
cout << "From C++ this time -> vs[2] " << vs[2] << endl; 

// Getting back a map of string-vector of string in C++ 
// and trying to use it 
object pymvs = main namespace["mvs"]; 
//- - - - - - - - - - - - - - - - > this still does not work - - - - - - - - - - - - - - 
// pyMapVectorString& mvs = extract< pyMapVectorString&> (pymvs); 

//-------------------------> Work around: working in python 
object method = pymvs.attr("__setitem__"); 
VectorString vs3; 
vs3.push_back(" should "); 
vs3.push_back("work"); 
object ignored = method ("this", vs3); 
const char * s = extract<const char *> (pymvs.attr("__getitem__")("this ").attr ("__str__")()); 
cout << s << endl; 
} 
catch (error_already_set) { 
    PyErr_Print(); 
    return 1; 
} 

Py_Finalize(); 
return 0; 
} 
関連する問題