2015-09-09 2 views
10

मुझे SWIG (संस्करण 3.0.6) का उपयोग कर एक सी ++ लाइब्रेरी के चारों ओर एक पायथन रैपर उत्पन्न करने में कुछ परेशानी हो रही है।पायथन में कक्षा प्रकारों के लिए SWIG OUTPUT टाइपमैप कैसे लागू करें?

मेरा मुद्दा OUTPUT टाइपमैप को लागू करने से संबंधित है, खासकर कक्षा प्रकारों के पॉइंटर्स/संदर्भों के मामले में।

समझने के लिए, यह है कि मैं क्या मानक प्रकार के लिए चाहते हैं, और यह काम करता है:

// .h 
int add(const long arg1,const long arg2,long& resultLong); 

// interface.i 
%apply long& OUTPUT { long& resultLong }; 
int add(const long arg1,const long arg2,long& resultLong); 

// projectWrapper.py 
def add(arg1, arg2): 
    return _projectWrapper.add(arg1, arg2) 
addTerm = _projectWrapper.add 

// usage 
>>> result = projectWrapper.add(2, 4) 
>>> print result 
[0, 6L] 

आप "resultLong" में पारित करने के लिए की जरूरत नहीं है, लेकिन यह परिणाम के लिए स्वचालित रूप से जोड़ दिया जाता है। महान!

बहरहाल, यह काम करने के रूप में मैं उम्मीद जब उत्पादन प्रकार एक वर्ग प्रकार के लिए कुछ सूचक है प्रतीत नहीं होता:

// .h 
int GetClassType(const char* name, exportedClassType*& resultPointer); 

class exportedClassType 
{...} 

// interface.i 
%apply exportedClassType*& OUTPUT { exportedClassType*& resultPointer };  
int GetClassType(const char* name, exportedClassType*& resultPointer); 

// projectWrapper.py 
def GetClassType(name, resultPointer): 
    return _projectWrapper.GetClassType(name, resultPointer) 
GetClassType = _projectWrapper.GetClassType 

समस्या हो कि बड़ा घूँट ही में उसे पूरा नहीं किया लगता है सरल प्रकार के रूप में रास्ता। यह अभी भी लपेटा गया फ़ंक्शन हस्ताक्षर में "इनपुट" पैरामीटर के रूप में दिखाई देता है।

// attempted usage 
>>> classType = projectWrapper.GetClassType("name") 
TypeError: GetClassType() takes exactly 2 arguments (1 given) 

>>> result = 0 
>>> projectWrapper.GetClassType("name", result) 
Traceback (most recent call last): 
File "<input>", line 1, in <module> 
TypeError: in method 'GetClassType', argument 2 of type 'exportedClassType *&' 

क्या कोई मुझे बता सकता है कि मैं क्या गलत कर रहा हूं या मुझे सही दिशा में इंगित करता हूं? किसी भी मदद से कृतज्ञता से प्राप्त! धन्यवाद

+0

में आप एक डबल सूचक उपयोग करने की कोशिश की है? मुझे डबल पॉइंटर्स और एसडब्ल्यूआईजी 2.0.7 का उपयोग करके उत्पन्न कोड के साथ समस्याएं थीं, लेकिन यह 3.X.X –

+0

में हल हो गई है। क्षमा करें, यह इंटरफ़ेस.आई फ़ाइल में कैसा दिखता है? – SWilliams

+0

मुझे यह उल्लेख करना चाहिए कि मेरे पास C++ का स्वामित्व नहीं है और वहां विधि हस्ताक्षर नहीं बदल सकते हैं। मुझे निश्चित रूप से 'exportedClassType * और' पैरामीटर लेने वाली विधि को संभालने की आवश्यकता है। – SWilliams

उत्तर

3

यह प्रश्न काफी समय से अनसुलझा हुआ है, इसलिए मैंने सोचा कि मैं बेहतर प्रश्न का समाधान प्रदान करता हूं। आउटपुट टाइपमैप केवल सरल प्रकारों पर लागू होता है, इसलिए एक समाधान in और argout टाइपमैप के संयोजन द्वारा दिया जाता है।

, स्थिति, जहां हम एक सी ++ वर्ग SampleImpl एक सी ++ इंटरफ़ेस SampleBase, जो तकनीकी रूप से एक इंटरफेस नहीं है को लागू करने के लिए है पर विचार करें क्योंकि यह एक आभासी नाशक के कार्यान्वयन शामिल है। मान लें कि हमारे पास एक स्थिर कार्य है, जो एक त्रुटि कोड और इंटरफेस के कार्यान्वयन देता है। उत्तरार्द्ध एक सूचक के संदर्भ के रूप में, जो ऊपर की स्थिति है।

इंटरफ़ेस हैडर:

// Sample.hpp 
#pragma once 
namespace Module { 
    class SampleBase { 
    public: 
#ifndef SWIG 
    // Hint to the programmer to implement this function 
    static int SampleCreate(SampleBase *&obj); 
#endif 
    virtual ~SampleBase() = default; 
    }; 
} 

कार्यान्वयन हैडर:

// Sample_impl.hpp 
#pragma once 
#include "Sample.hpp" 

namespace Module { 
    class SampleImpl : public SampleBase { 
    public: 
    static int SampleCreate(Module::SampleBase *&obj); 

    SampleImpl(); 
    virtual ~SampleImpl(); 
    private: 
    float a; 
    }; 
} 

कार्यान्वयन:

// Sample_impl.cpp 
#include "Sample_impl.hpp" 
#include <cstdio> 

namespace Module { 
    int SampleImpl::SampleCreate(Module::SampleBase*& obj) { 
    obj = (SampleBase*) new SampleImpl(); 
    return 0; 
    } 
    SampleImpl::SampleImpl() { 
    printf("SampleImpl::SampleImpl()\n"); 
    } 

    SampleImpl::~SampleImpl() { 
    printf("SampleImpl::~SampleImpl()\n"); 
    } 
} 

बड़ा घूँट इंटरफेस (argout का उपयोग कर typemap)

// example.i 
%module example 
%{ 
    #define SWIG_FILE_WITH_INIT 
    #include "Sample.hpp" 
    #include "Sample_impl.hpp" 
%} 

%include "typemaps.i" 

%typemap(in, numinputs=0) Module::SampleBase *&obj (Module::SampleBase *temp) { 
    $1 = &temp; 
} 

%typemap(argout) Module::SampleBase *& { 
    PyObject* temp = NULL; 
    if (!PyList_Check($result)) { 
    temp = $result; 
    $result = PyList_New(1); 
    PyList_SetItem($result, 0, temp); 

    // Create shadow object (do not use SWIG_POINTER_NEW) 
    temp = SWIG_NewPointerObj(SWIG_as_voidptr(*$1), 
      $descriptor(Module::SampleBase*), 
      SWIG_POINTER_OWN | 0); 

    PyList_Append($result, temp); 
    Py_DECREF(temp); 
    } 
} 

प्रयोग अजगर

import example 

// Creating specialization 
obj = example.SampleImpl() 
del obj 

// Creation of object using output typemap 
errorCode, obj = example.SampleImpl_SampleCreate() 
del obj 
+0

ऐसा लगता है कि मैं क्या देख रहा था, धन्यवाद! – SWilliams

+0

आपका स्वागत है। मैंने ऐसा बदल दिया है कि कोई ऑब्जेक्ट केवल आउटपुट सूची में जोड़ा जाता है यदि कोई भी त्रुटि के लिए कन्स्ट्रक्टर या फ़ंक्शन 0 लौटाता है। –

2

यह एक जवाब है, बस एक टिप्पणी :(

कारण आप C++ में सूचक का उपयोग करने और अजगर संकेत नहीं है की जरूरत है (ताकि आप कुछ भी अपने वर्तमान के साथ नहीं कर सकता है के लिए reputaiton के लिए पर्याप्त नहीं है । अजगर में 'परिणाम' वैसे भी)

आप ज में संकेत को छिपाने के लिए रैपर के रूप में जोड़ा जा सका @Jens Munk द्वारा सुझाव दिया गया था:

class exportedClassType_ptr { 
public: 
    exportedClassType* ptr; 
    exportedClassType_ptr(exportedClassType& input) { 
     this->ptr = &input; 
    } 
}; 

int GetClassType(const char* name, exportedClassType_ptr& resultPointer) { 
    return GetClassType(name, resultPointer.ptr); 
} 

मैं फ़ाइल को संशोधित नई विधि कॉल करने के:

%apply exportedClassType_ptr& OUTPUT { exportedClassType_ptr& resultPointer };  
int GetClassType(const char* name, exportedClassType_ptr& resultPointer); 

अजगर में कुछ इस तरह लिखना:

>>> realResult = projectWrapper.exportedClassType() 
>>> result = projectWrapper.exportedClassType_ptr(realResult) 
>>> projectWrapper.GetClassType("name", result) 

और भविष्य के काम के लिए 'realResult' का उपयोग करें।

+0

उत्तर के लिए धन्यवाद। अब मैं देखता हूं कि वास्तव में जेन्स मंक ने उनकी टिप्पणियों के बारे में क्या बताया। मुझे इसे लागू करने के साथ एक मुद्दा है। क्या होगा यदि लपेटने की विधि एक क्लास विधि है, तो 'exportedClassType.GetClassType' कहें? मैं कक्षा पर एक नई ओवरराइट विधि कैसे बना सकता हूं जो 'exportedClasssType_ptr' ले जाएगा? – SWilliams

+0

वास्तविक उदाहरण के बिना एक उत्तेजना देना मुश्किल है। उदाहरण के लिए आप अपनी खुद की व्युत्पन्न कक्षा 'क्लास newClassWithoutPointers: सार्वजनिक oldClassWithPointers {} 'बना सकते हैं और इनपुट पॉइंटर डेटा के साथ सभी विधियों को बदल सकते हैं। लेकिन यह गलत तरीके से काम कर सकता है अगर वे सभी विधियां इनपुट पॉइंटर्स के लिए 'नया' या 'हटाएं' कह रही हैं। – embrio

+0

यह मेरे उपयोग के मामले (उपर्युक्त टिप्पणियां देखें) के लिए पूरी तरह से पूर्ण नहीं है, लेकिन यह एक स्पष्ट पूर्ण उदाहरण है जिसने दृष्टिकोण को समझाया और मुझे अनावृत कर दिया। आपको उदारता मिलती है, धन्यवाद। – SWilliams

0

मुझे लगता है कि आपको पॉइंटर्स का उपयोग करने की आवश्यकता है। मुझे यह भी सुनिश्चित नहीं है कि क्या होता है, टाइपमैप और रिटर्न स्टेटमेंट्स को मिलाते समय क्या होता है। एक न्यूनतम उदाहरण फ़ाइल tst.i:

%module tst 

%{ 

    // declaration: 
    void add(long *resultLong, const long arg1,const long arg2); 
    long mul(const long a, const long b); 

    // the code: 
    void add(long *resultLong, const long arg1,const long arg2) { 
    *resultLong = arg1 + arg2; 
    } 
    long mul(const long a, const long b) { 
    return a*b; 
    } 

%} 

// The wrapper: 
%apply (long* OUTPUT) { long* resultLong }; 
void add(long* resultLong, const long arg1,const long arg2); 
long mul(const long a, const long b); 

अनुवाद (मैं हमेशा CMake का उपयोग करें) के बाद, अजगर में उपयोग होगा:

import tst 
x = tst.add(3, 4) # results in 7L  
y = tst.mul(3, 4) # results in 12L 

मुझे लगता है कि अदिश डेटाटाइप्स के लिए typemaps के बजाय वापसी बयानों का उपयोग कर बेहतर है । सरणी को इंटरफेस करते समय, मैं numpy.i के पूर्वनिर्धारित टाइपमैप का उपयोग करने की सलाह देता हूं।

+0

क्षमा करें, मुझे नहीं लगता कि यह प्रश्न में पूछे गए वर्ग प्रकारों पर कैसे लागू होता है। – SWilliams

संबंधित मुद्दे