2014-10-10 9 views
9

अगर मैं इस सरल मामला है:कार्यशीलता के लिए std :: bind खाता क्यों नहीं है?

struct Foo 
{ 
    void bar(); 
    void baz(int); 
}; 

यह भावना है कि यह संकलन होगा बनाता है:

Foo foo; 
auto f = std::bind(&Foo::bar, &foo); 

लेकिन क्यों bind इस तरह से डिजाइन किया जाना है कि यह संकलित:

auto g = std::bind(&Foo::baz, &foo); 

मैं f पर कॉल कर सकता हूं, लेकिन मैं कभी भी g पर कॉल नहीं कर सकता। यह संकलन क्यों करें? मुझे आवश्यकता होती है के पीछे तर्क क्या करना है क्या है:

auto g2 = std::bind(&Foo::baz, &foo, std::placeholders::_1); 

मैं प्लेसहोल्डर का उपयोग कर समझ सकते हैं अगर आप जो तर्क पारित कर दिया और किस क्रम में हो, लेकिन क्यों बस डिफ़ॉल्ट पास नहीं के साथ गड़बड़ करने के लिए चाहते सभी सही आदेश में तर्क निर्दिष्ट किए बिना?

+1

क्योंकि वहाँ तर्क की संख्या प्राप्त करने के लिए कोई रास्ता नहीं है अन्यथा फ़ंक्शन का अर्थ है, जिसका अर्थ है कि जेनरेट किए गए फ़ंक्शन ऑब्जेक्ट को * किसी भी * तर्कों की संख्या को अनुमति देना होगा, जिसमें कोई भी शामिल नहीं है, जो अपरिभाषित व्यवहार का कारण बनता है (उदाहरण के लिए) 'g' को बिना तर्क के "कहा जाता है। –

+6

मुझे लगता है कि 'std :: प्लेसहोल्डर्स' दो कार्य करता है, 1. जैसा कि आप कहते हैं, वे स्रोत से सिंक तक तर्कों को रूट करते हैं, 2. वे इंगित करते हैं कि कितने तर्क की आवश्यकता है। – Niall

+3

बूस्ट लाइब्रेरी में 'बाइंड' से संबंधित मूल डिजाइन तर्क अधिक हो सकता है। – Niall

उत्तर

3

लेकिन क्यों बाध्य होगा इस तरह से डिजाइन किया जाना है कि इस संकलित:
auto g = std::bind(&Foo::baz, &foo);
मैं f कॉल कर सकते हैं, लेकिन मैं कभी g फोन नहीं कर सकते हैं। यह संकलन क्यों करें?

Boost.Bind FAQ का कहना है कि Boost.Bind आमतौर पर "बाँध समय" पर ऐसी त्रुटियों का निदान होगा (लाइन जहां bind फोन पर अर्थात)। हालांकि मानक की आवश्यकता नहीं है कि std::bind के लिए, बजाय यह है में निम्नलिखित std::bind के लिए तत्व आवश्यक है:

INVOKE (fd, w1, w2, ..., wN) (20.9.2) कुछ मान w1 के लिए एक वैध अभिव्यक्ति, W2 होगा, ..., डब्ल्यूएन, जहां N == sizeof...(bound_args)

इसका मतलब है कि आपका कोड फ़ंक्शन की पूर्व शर्त का उल्लंघन करता है, जिसके परिणामस्वरूप अपरिभाषित व्यवहार होता है। मानक पुस्तकालय कार्यान्वयन पूर्व शर्त उल्लंघन की जांच करने के लिए बाध्य नहीं है, यह आपका काम है। लाइब्रेरी को इन्हें जांचने के लिए मना नहीं किया गया है, इसलिए यह इसे अस्वीकार करने के कार्यान्वयन के अनुरूप होगा, बूस्ट के रूप में। बाइंड करता है। मैं आपके पुस्तकालय विक्रेता से अनुरोध करता हूं कि वे अवैध बाध्य अभिव्यक्तियों का निदान करने के लिए कहें जहां ऐसा करना संभव है, "कार्यान्वयन की गुणवत्ता" वृद्धि के रूप में।

क्यों नहीं बस यह बताए बिना डिफ़ॉल्ट पास सभी सही क्रम में तर्क है?

मैं दो कारणों से सोच सकता हूं।

सबसे पहले, bind द्वारा बनाई गई कॉल आवरण के व्यवहार तर्क है कि एक प्लेसहोल्डर के अनुरूप नहीं है ड्रॉप करने के लिए है, तो आप x(1, 2, 3) फोन और यह सभी तर्क पर ध्यान न दें और foo.bar() फोन हो सकता है। यह एक सामान्य पैटर्न का हिस्सा है जहां आप bind का उपयोग करके एक एन-एरीटी फ़ंक्शन को एक पूरी तरह से अलग धैर्य के साथ कॉल रैपर बनाने के लिए लपेट सकते हैं जो तर्क जोड़ सकता है, उन्हें हटा सकता है, कुछ विशिष्ट बाध्य मानों को ठीक कर सकता है।x(1, 2, 3) सभी तर्कों को छोड़ना असंभव होगा यदि डिफ़ॉल्ट व्यवहार में कोई प्लेसहोल्डर्स का उपयोग नहीं किया जाता है, तो सभी तर्कों को आगे बढ़ाना था।

दूसरा, यह हमेशा आपको यह सुनिश्चित करने के लिए अधिक सुसंगत है कि आप किस तर्क में पारित करना चाहते हैं। आम तौर पर जब कोई बाध्य तर्क नहीं होता है तो सभी आमंत्रण तर्कों को पारित करने के लिए केवल समझदारी होगी, अन्यथा bind को कैसे पता होना चाहिए कि बाध्य तर्कों के पहले या बाद में आमंत्रण तर्क पारित करना है या नहीं?

उदा।

struct X { 
    void f(int, int) { } 
} x; 
auto h = bind(&X::f, &x, 1); 
h(2); 

दिया चाहिए x.f(1, 2) या x.f(2, 1) में h(2) परिणाम के लिए कॉल? जब सही तर्क होते हैं तो सही व्यवहार स्पष्ट नहीं होता है, जब सभी प्लेसमेंटधारक नहीं होते हैं तो स्वचालित रूप से सभी तर्कों को अग्रेषित करते हैं, जब कोई बाध्य तर्क नहीं होता है (क्योंकि तब कोई सवाल नहीं है कि बाध्य तर्क पहले या आखिरी आते हैं या नहीं) , जो एक काफी विशेष मामला है। उस विशेष मामले के साथ काम करने के लिए एपीआई की एक महत्वपूर्ण विशेषता को बदलना संदिग्ध मूल्य होगा, खासकर जब यह x(1, 2, 3) ->foo.bar() केस प्राप्त करना असंभव है।

एक वैकल्पिक समाधान यह है कि उपयोगकर्ताओं को जो कुछ चाहिए, उसके बारे में स्पष्ट होना आवश्यक है, लेकिन N4171 में टॉमसज़ कमीन्स्की द्वारा प्रस्तावित "बस कुछ भी आगे" कहने का एक स्पष्ट तरीका प्रदान करें, जिस पर सी ++ कमेटी मीटिंग में चर्चा की जाएगी सप्ताह। _all प्लेसहोल्डर तय मंगलाचरण तर्कों से पहले या बाध्य तर्क के बाद आना चाहिए, क्योंकि आप स्पष्ट रूप से कह सकते हैं कि क्या आप चाहते हैं की समस्या का हल bind(f, arg1, arg2, std::placeholders::_all) या bind(f, std::placeholders::_all, arg1, arg2) या यहाँ तक कि bind(f, arg1, std::placeholders::_all, arg2)

शायद
+0

तो आप क्यूओआई एन्हांसमेंट के रूप में अमान्य बाइंड एक्सप्रेशन का निदान करने के बारे में क्या सोचते हैं? :) – Barry

+1

अच्छा विचार! मैं इसे देख लूंगा :) –

+0

जीसीसी ट्रंक अब बाइंड एक्सप्रेशन की धैर्य की जांच करता है, https://gcc.gnu.org/ml/gcc-patches/2014-11/msg00032.html –

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