2011-01-30 7 views
9

मुझे सी ++ कोडबेस के लिए पायथन बाइंडिंग बनाने की आवश्यकता है। मैं बूस्ट :: पायथन का उपयोग करता हूं और मैं टेम्पलेट्स का उपयोग करके और लौटने वाले कार्यों वाले वर्गों को बेनकाब करने की कोशिश करने में समस्याओं में भाग गया। यहां एक सामान्य उदाहरणबूस्ट :: पायथन एक्सपोज़िंग सी ++ फ़ंक्शंस का उपयोग करके और लौटने वाले फ़ंक्शन

class Foo 
{ 
    public: 
     Foo(); 
     template<typename T> Foo& setValue(
      const string& propertyName, const T& value); 
     template<typename T> const T& getValue(
      const string& propertyName); 
}; 

विशिष्ट टी स्ट्रिंग, डबल, वेक्टर हैं।

documentation पढ़ने के बाद, मैंने हर प्रकार के इस्तेमाल के लिए पतले रैपर का उपयोग करने की कोशिश की। स्ट्रिंग और डबल और इसी श्रेणी की घोषणा के लिए रैपर हैं।

Foo & (Foo::*setValueDouble)(const std::string&,const double &) = 
    &Foo::setValue; 
const double & (Foo::*getValueDouble)(const std::string&) = 
    &Foo::getValue; 

Foo & (Foo::*setValueString)(const std::string&,const std::string &) = 
    &Foo::setValue; 
const std::string & (Foo::*getValueString)(const std::string&) = 
    &Foo::getValue; 

class_<Foo>("Foo") 
    .def("setValue",setValueDouble, 
     return_value_policy<reference_existing_object>()) 
    .def("getValue",getValueDouble, 
     return_value_policy<copy_const_reference>()) 
    .def("getValue",getValueString, 
     return_value_policy<copy_const_reference>()) 
    .def("setValue",setValueString, 
     return_value_policy<reference_existing_object>()); 

यह ठीक संकलित करता है लेकिन जब मैं पाइथन बाइंडिंग का उपयोग करने का प्रयास करता हूं, तो मुझे सी ++ अपवाद मिलता है।

>>> f = Foo() 
>>> f.setValue("key",1.0) 
>>> f.getValue("key") 
Traceback (most recent call last): 
    File "<stdin>", line 1, in ? 
    RuntimeError: unidentifiable C++ exception 

दिलचस्प बात यह है कि जब मैं केवल डबल या स्ट्रिंग मान के लिए फू का पर्दाफाश, यानी

class_<Foo>("Foo") 
    .def("getValue",getValueString, 
     return_value_policy<copy_const_reference>()) 
    .def("setValue",setValueString, 
     return_value_policy<reference_existing_object>()); 

यह ठीक काम करता है। क्या मुझे कुछ याद आ रही है?

+1

आप http://mail.python.org/pipermail/cplusplus-sig/2006-February/009990.html पर धागा (जो एक समान समस्या tackles को देखने के लिए चाहते हो सकता है: रैपिंग बढ़ावा :: किसी भी) – lijie

उत्तर

3

यह आपकी समस्या से सीधे संबंधित नहीं हो सकता है लेकिन मैं इस तरह के टेम्पलेट्स के साथ फ़ंक्शन हस्ताक्षर कास्टिंग पर भरोसा नहीं करता। मैं इसे इस तरह लपेटा है |: उन निर्यात के रूप में लगा कि वे सदस्य कार्यों थे

Foo& setValueDouble(foo& self, const string& propertyName, const double value) 
{ 
    return self.setValue(propertyName, value) 
} 
... 

और:

class_<Foo>("Foo") 
    .def("setValue", &Foo::setValue<double>, 
     return_value_policy<reference_existing_object>()) 
    .def("getValue", &Foo::getValue<double>, 
     return_value_policy<copy_const_reference>()) 
    .def("getValue", &Foo::getValue<std::string>, 
     return_value_policy<copy_const_reference>()) 
    .def("setValue", &Foo::setValue<std::string>, 
     return_value_policy<reference_existing_object>()); 

यदि वह काम नहीं करता है, तो आप कुछ शिम कार्यों बनाने के लिए आवश्यकता हो सकती है।

एक ही नाम पर एकाधिक फ़ंक्शन ओवरलोड निर्यात करना बूस्ट :: पायथन में करने के लिए एक पूरी तरह से मान्य बात है, इसलिए मुझे नहीं लगता कि यह समस्या है।

+0

मुझे प्रश्न में कोड में कोई कास्टिंग नहीं दिख रहा है। इस प्रकार आप "पॉइंटर-टू-सदस्य-फ़ंक्शन" प्रकार का एक चर घोषित करते हैं। –

+0

यह धन्यवाद काम किया। – LouisChiffre

0

मुझे संदेह है कि समस्या यह है कि बूस्ट :: पायथन को पता नहीं है कि "getValue" के लिए कॉल करने के लिए कौन सा ओवरलोड है - क्या इसे कॉल करना चाहिए ValueDouble या GetValueString? यदि आप उन्हें स्पष्ट रूप से getValueString के रूप में बाध्य करते हैं और GetValueDouble (विधि नाम के रूप में) मुझे लगता है कि यह काम करेगा।

+0

आपकी मदद के लिए धन्यवाद। मैंने कोशिश की कि आप क्या सुझाव देते हैं और यह काम करता है। लेकिन यह परिणामी पायथन कोड को अधिक वर्बोज़ बनाता है क्योंकि मुझे मूल्य प्रकार के आधार पर अलग-अलग गेटर का उपयोग करना पड़ता है। शायद एक और सुरुचिपूर्ण तरीका है? – LouisChiffre

+0

यह आवश्यक नहीं होना चाहिए। बूस्ट :: पायथन में एक ही नाम पर एकाधिक हस्ताक्षर निर्यात करना एक पूरी तरह से मान्य बात है। –

+0

@ लुइस: मुझे समझ में नहीं आता कि आप पाइथन को यह जानना चाहते हैं कि आप किस अधिभार को चाहते हैं ... सी ++ में भी, आपको टाइप निर्दिष्ट करके वर्बोज़ (जैसा कि आप कहते हैं) होना चाहिए: 'foo.getValue (...) ' – rafak

0

गेटर्स/सेटर्स के लिए सी ++ रैपर बनाने के बारे में क्या है जो एक वापसी/वापस लेते हैं :: python :: object? फिर आप बस अपने सी ++ रैपर में प्राप्त प्रकार को निर्धारित कर सकते हैं और इसे बूस्ट :: पायथन :: ऑब्जेक्ट में/लपेट सकते हैं।

struct FooWrap : public Foo 
{ 
    using boost::python; 
    Foo& setValueO(const string& propertyName, const object& obj) 
    { 
     object value; 
     if(PyInt_Check(obj.ptr())) { 
      return setValue<int>(propertyName, extract<int>(obj); 
     } else if(PyFloat_Check(obj.ptr())) { 
      return setValue<double>(propertyName, extract<double>(obj); 
     } else if(PyString_Check(obj.ptr())) { 
      return setValue<std::string>(propertyName, extract<std::string>(obj); 
     } 
     // etc... 
    } 

    object getValueO(const std::string& propertyName) 
    { 
     if(determineType() == TYPE_INT) { // however you determine the type 
      return object(getValue<int>(propertyName)); 
     } else if(determineType() == TYPE_DOUBLE) { 
      return object(getValue<double>(propertyName)); 
     } else if(determineType() == TYPE_STRING) { 
      return object(getValue<std::string>(propertyName)); 
     } 
     // etc... 
    } 
}; 

class_<Foo>("Foo") 
    .def("setValue", &FooWrap::setValueO, 
     return_value_policy<reference_existing_object>()) 
    .def("getValue", &FooWrap::getValueO, 
     return_value_policy<copy_const_reference>()) 
संबंधित मुद्दे