2014-10-21 7 views
5

मैं एक फ़ंक्शन लपेटना चाहता हूं जो boost::optional<T> देता है। यही कारण है, दिया जाता है:एक सी ++ फ़ंक्शन को कैसे लपेटें जो बढ़ावा देता है :: वैकल्पिक <T>?

class Foo { 
    boost::optional<T> func(); 
}; 

मुझे लगता है कि रैप करने के लिए किसी भी तरह इतना है कि अजगर या तो एक मूल्य के द्वारा T, या None हो जाता है चाहते हैं: मैं कर सकता

class_<Foo>("Foo") 
    .def("func", func, return_value_policy<return_boost_optional???>); 

अगर यह सिर्फ एक T लौटे आम ​​तौर पर, का उपयोग करें:

class_<Foo>("Foo") 
    .def("func", func, return_value_policy<return_by_value>()); 

लेकिन क्योंकि यह एक boost::optional<T> देता है, यह भी boost::none लौटा सकता है, जो मैं पायथन केके रूप में खत्म करना चाहते हैं।

क्या मौजूदा कन्वर्टर्स के साथ ऐसा करने का कोई तरीका है? यदि नहीं, तो क्या वही प्रभाव प्राप्त करने के लिए कुछ कामकाज है?

उत्तर

10

ResultConverter अवधारणा इस समस्या को हल करने के लिए डिज़ाइन की गई है। return_value_policy कॉलपॉली मॉडल एक परिणाम कनवर्टर बनाने के लिए एक परिणाम कनवर्टर जेनरेटर का उपयोग करता है, और परिणाम कनवर्टर का उपयोग पाइथन के संपर्क में आने वाले फ़ंक्शन के रिटर्न वैल्यू को संशोधित करने के लिए किया जाता है। इस मामले में, एक कस्टम प्रकार जो परिणाम कनवर्टर अवधारणा को लागू करता है या तो पाइथन None वापस करने के लिए या उचित पायथन कक्षा के साथ किसी ऑब्जेक्ट को तुरंत चालू करने के लिए उपयोग किया जा सकता है।

/// @brief The ResultConverterGenerator. 
struct result_converter_generator 
{ 
    template <typename T> 
    struct apply 
    { 
    struct result_converter 
    { 
     // Must be default constructible. 
     result_converter(); 

     // Return true if T can be converted to a Python Object. 
     bool convertible(); 

     // Convert obj to a PyObject, explicitly managing proper reference 
     // counts. 
     PyObject* operator(const T& obj); 

     // Returns the Python object that represents the type. Used for 
     // documentation. 
     const PyTypeObject* get_pytype(); 
    }; 

    /// @brief The ResultConverter. 
    typedef result_converter type; 
    }; 
}; 

कई बार, जब एक कस्टम ResultConverter मॉडल बनाते समय, एक टेम्पलेट मेटा प्रोग्रामिंग की संभावना को कम करने के लिए उपयोग कर सकते हैं: एक ओर जहां प्रलेखन सूची सभी प्रकार की आवश्यकताओं, यह करीब कोड कुछ मिलता-जुलता से समझा करने के लिए आसान हो सकता है रूपांतरणों में रनटाइम त्रुटियां, और संकलन समय पर भी त्रुटियों को पकड़ें और सार्थक संदेश प्रदान करें। यहां return_optional का एक पूर्ण उदाहरण है, एक परिणाम कनवर्टर मॉडल जो एक C++ boost::optional<T> ऑब्जेक्ट लेता है, और इसे उचित पायथन ऑब्जेक्ट में परिवर्तित करता है।

#include <boost/mpl/if.hpp> 
#include <boost/optional.hpp> 
#include <boost/python.hpp> 
#include <boost/type_traits/integral_constant.hpp> 
#include <boost/utility/in_place_factory.hpp> 

/// @brief Mockup model. 
class spam {}; 

/// @brief Mockup factory for model. 
boost::optional<spam> make_spam(bool x) 
{ 
    return x ? boost::optional<spam>(boost::in_place()) : boost::none; 
} 

namespace detail { 

/// @brief Type trait that determines if the provided type is 
///  a boost::optional. 
template <typename T> 
struct is_optional : boost::false_type {}; 

template <typename T> 
struct is_optional<boost::optional<T> > : boost::true_type {}; 

/// @brief Type used to provide meaningful compiler errors. 
template <typename> 
struct return_optional_requires_a_optional_return_type {}; 

/// @brief ResultConverter model that converts a boost::optional object to 
///  Python None if the object is empty (i.e. boost::none) or defers 
///  to Boost.Python to convert object to a Python object. 
template <typename T> 
struct to_python_optional 
{ 
    /// @brief Only supports converting Boost.Optional types. 
    /// @note This is checked at runtime. 
    bool convertible() const { return detail::is_optional<T>::value; } 

    /// @brief Convert boost::optional object to Python None or a 
    ///  Boost.Python object. 
    PyObject* operator()(const T& obj) const 
    { 
    namespace python = boost::python; 
    python::object result = 
     obj      // If boost::optional has a value, then 
     ? python::object(*obj) // defer to Boost.Python converter. 
     : python::object(); // Otherwise, return Python None. 

    // The python::object contains a handle which functions as 
    // smart-pointer to the underlying PyObject. As it will go 
    // out of scope, explicitly increment the PyObject's reference 
    // count, as the caller expects a non-borrowed (i.e. owned) reference. 
    return python::incref(result.ptr()); 
    } 

    /// @brief Used for documentation. 
    const PyTypeObject* get_pytype() const { return 0; } 
}; 

} // namespace detail 

/// @brief Converts a boost::optional to Python None if the object is 
///  equal to boost::none. Otherwise, defers to the registered 
///  type converter to returs a Boost.Python object. 
struct return_optional 
{ 
    template <class T> struct apply 
    { 
    // The to_python_optional ResultConverter only checks if T is convertible 
    // at runtime. However, the following MPL branch cause a compile time 
    // error if T is not a boost::optional by providing a type that is not a 
    // ResultConverter model. 
    typedef typename boost::mpl::if_< 
     detail::is_optional<T>, 
     detail::to_python_optional<T>, 
     detail::return_optional_requires_a_optional_return_type<T> 
    >::type type; 
    }; // apply 
}; // return_optional 

BOOST_PYTHON_MODULE(example) 
{ 
    namespace python = boost::python; 
    python::class_<spam>("Spam") 
    ; 

    python::def("make_spam", &make_spam, 
    python::return_value_policy<return_optional>()); 
} 

इंटरएक्टिव उपयोग:

>>> import example 
>>> assert(isinstance(example.make_spam(True), example.Spam)) 
>>> assert(example.make_spam(False) is None) 

संकलन समय प्रकार की जाँच तब होता है जब return_optional ResultConvert एक समारोह है कि एक boost::optional नहीं है एक मान देता है साथ प्रयोग किया जा करने का प्रयास किया जाता है। उदाहरण के लिए, जब निम्न प्रयोग किया जाता है:

struct egg {}; 

egg* make_egg(); 

BOOST_PYTHON_MODULE(example) 
{ 
    namespace python = boost::python; 
    python::def("make_egg", &make_egg, 
    python::return_value_policy<return_optional>()); 
} 

संकलक return_optional_requires_a_optional_return_type कार्यान्वयन चयन का चयन करेंगे, और असफल संकलन। यहां संकलक त्रुटि संदेश क्लैंग का हिस्सा दिया गया है:

 
error: no member named 'get_pytype' in 
'detail::return_optional_requires_a_optional_return_type<egg *>' 
+0

यह वास्तव में boost :: पायथन लाइब्रेरी का हिस्सा होना चाहिए। बहुत अच्छे! – Felix

+0

यह वास्तव में असाधारण उत्तर है। – Mohan

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