2013-08-29 11 views
24

क्यों सी ++ 11 में std::bind के साथ एक साथ उपयोग करने के लिए कोई std::protect है?कोई std :: सुरक्षा क्यों नहीं है?

Boost.Bind एक boost::protect सहायक है कि इसके तर्क लपेटता ताकि boost::bind को नहीं पहचानता है और यह मूल्यांकन प्रदान करता है। std::[c]ref एक अच्छा पर्याप्त प्रतिस्थापन, समय की सबसे हो सिवाय इसके कि यह एक rvalue तर्क के रूप में नहीं ले जाएगा होगा।

एक ठोस उदाहरण के लिए, निम्नलिखित कृत्रिम स्थिति पर विचार:

#include <type_traits> 
#include <functional> 

int add(int a, int b) 
{ return a + b; } 

struct invoke_with_42 
{ 
    template <typename FunObj> 
    auto operator()(FunObj&& fun_obj) const -> decltype((fun_obj(42))) 
    { return fun_obj(42); } 
}; 

int main() 
{ 
    //// Nested bind expression evaluated 
    //auto bind_expr = 
    // std::bind<int>(invoke_with_42{} 
    //  , std::bind(&add, 1, std::placeholders::_1)); 

    //// Compilation error, cref does not take rvalues 
    //auto bind_expr = 
    // std::bind<int>(invoke_with_42{} 
    //  , std::cref(std::bind(&add, 1, std::placeholders::_1))); 

    //// Ok, inner_bind_expr must be kept alive 
    auto inner_bind_expr = 
     std::bind(&add, 1, std::placeholders::_1); 
    auto outer_bind_expr = 
     std::bind<int>(invoke_with_42{}, std::cref(inner_bind_expr)); 


    //// Ok, with protect 
    //auto bind_expr = 
    // std::bind<int>(invoke_with_42{} 
    //  , std::protect(std::bind(&add, 1, std::placeholders::_1))); 
} 
+10

यह प्रस्तावित किया गया था? –

+1

एक 'एक' rvalue' पर cref' शायद विनाशकारी होगा - temporaries जीवन थोड़ा इसके चारों ओर जब तक रखने के रूप में 'bind' आपत्ति यह करने के लिए पारित किया जा रहा है (या जो भी) के लिए होगा। – Yakk

+0

आप 'bind' परिणाम को 'std :: function' पर असाइन करके" सुरक्षित "भी कर सकते हैं, हालांकि यह रनटाइम ओवरहेड जोड़ता है। – Potatoswatter

उत्तर

14

ठीक है, मैं क्यों यह लागू नहीं किया गया के बारे में पता नहीं कर रहा हूँ। शायद यह प्रस्तावित नहीं किया गया था, या शायद कुछ सूक्ष्म गठिया थे।

कहा, मुझे लगता है आप बहुत आसानी से

template<typename T> 
struct protect_wrapper : T 
{ 
    protect_wrapper(const T& t) : T(t) 
    { 

    } 

    protect_wrapper(T&& t) : T(std::move(t)) 
    { 

    } 
}; 

template<typename T> 
typename std::enable_if< !std::is_bind_expression< typename std::decay<T>::type >::value, 
       T&& >::type 
protect(T&& t) 
{ 
    return std::forward<T>(t); 
} 

template<typename T> 
typename std::enable_if< std::is_bind_expression< typename std::decay<T>::type >::value, 
       protect_wrapper<typename std::decay<T>::type > >::type 
protect(T&& t) 
{ 
    return protect_wrapper<typename std::decay<T>::type >(std::forward<T>(t)); 
} 

रक्षित के दो संस्करणों ताकि गैर बाँध भाव लिपटे नहीं कर रहे हैं (वे सिर्फ माध्यम से पारित) कर रहे हैं यह लिख सकते हैं। बाकी सब कुछ protect_wrapper पर स्थानांतरित/प्रतिलिपि द्वारा पारित किया जाता है, जो कि इस प्रकार से प्राप्त होता है। यह प्रकार के कार्यों को पार करने की अनुमति देता है, या इसके लिए प्रकार में कनवर्ट करने की अनुमति देता है।

यह एक कॉपी/तथापि के लिए कदम बनाता है, इसलिए इसे सुरक्षित रूप से rvals के साथ प्रयोग किया जा सकता है। और चूंकि यह केवल उन प्रकारों की सुरक्षा करता है जो bind_expressions हैं, यह प्रतिलिपि बनाने की मात्रा को कम करता है।

int main() 
{ 

    //// Ok, with protect 
    auto bind_expr = 
     std::bind<int>(invoke_with_42{} 
      , protect(std::bind(&add, 1, std::placeholders::_1))); 


    std:: cout << bind_expr() << std::endl; 
    return 0; 

} 
+10

सी ++ 11 इनहेरिट कंस्ट्रक्टर्स के साथ, पूरी क्लास परिभाषा सिर्फ 'टेम्पलेट struct protect_wrapper है: टी {टी :: टी का उपयोग; }; ' – Potatoswatter

+0

मुझे ऐसा लगता है कि को बढ़ावा देने के उद्देश्य को :: रक्षा लोग unmaintainable कोड लिखने की अनुमति देने के लिए है ... नहीं यह है कि यह यह refactor करने के लिए समय आ गया है कि अगर एक लैम्ब्डा अभिव्यक्ति इस जटिल है कहना उचित होगा? –

+0

@RichardHodges: हालांकि यह दुर्लभ है, मुझे लगता है कि 'बढ़ावा :: protect' के प्रयोजन से अधिक कैसे' bind' आमतौर पर नेस्टेड बांध संभालती ट्रिपिंग के बिना, आप एक समारोह जो एक तर्क के रूप में एक समारोह लेता लिखने के लिए अनुमति देने के लिए है। एक समारोह है कि एक और सी ++ में आम नहीं है लेता होने, वहाँ अधिक कार्यात्मक कार्यक्रमों की शैलियों कि सामान्य है कि लगता है कर रहे हैं। –

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