2017-02-24 59 views
0

上下文是嵌入式Python腳本的上下文,並從用C++編寫的代碼調用解釋器 。從包裝提取到矢量地圖

的C++和下面的Python代碼概括的技術用C++來包裝,在Python中使用,然後提取背面C++中的兩種最常見的STL容器:

  • 的std ::矢量
  • 的std :: map

它更專注於它們持有std :: string類型元素的情況。

對於不熟悉boost python庫的編碼人員來說,困難之處在於boost迭代器和可迭代套件映射的是兩種語言共有的概念,但在兩種編程環境中對這兩種語言的處理卻相當不同。

借鑑現有的材料和個人實驗,我已經澄清了自己對於最常見的用法似乎是什麼意圖。沒有其他地方沒有顯示過,但它確實感覺到boost :: python在例子和示例方面可以容忍一些冗餘。

有一種情況,目前我似乎無法解決:向C++返回一個字符串的包裝向量。如果有人能讓我知道這一點,我將不勝感激。

該代碼旨在自包含,並有兩個目的。首先,它旨在幫助那些和我一樣尋求更多簡單用例的人。它還表明操縱一個double向量比向量字符串更直接。

在下面的C++示例中,我得到一個運行時錯誤實質上是: typedef std :: vector VecStr; 從這個類型爲MapStringVectorString的Python對象的類boost :: python :: class> struct boost :: python :: deltail :: not_specified_struc。

任何建議,將不勝感激。 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選項進行糾正。第二個問題依然存在,似乎應該構建一個來自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; 
}