2012-03-12 12 views
6

क्या पैरामीटर के रूप में दिए गए लैम्ब्डा के कैप्चर के प्रकार को बाधित करना संभव है?
उदाहरण के लिए, क्या केवल लैम्बडा लेना संभव है जो संदर्भ द्वारा कुछ भी कैप्चर नहीं करते?सी ++ लैम्ब्डा कैप्चर बाधा

template <typename F> 
void f(const F& lambda) // F must be a lambda that do not capture by ref 
{ 
    ::: 
} 
+2

जब तक क्लोजर ऑब्जेक्ट आपके फ़ंक्शन को हिट करता है, तब तक यह पहले से ही बनाया जा चुका है, और आपको पता नहीं है कि इसके गले के अंदर क्या है, क्योंकि ये निजी हैं। लेकिन यदि आप सोच रहे थे, तो लैम्ब्डा निश्चित रूप से * * के बाद कुछ भी नहीं ले सकता है, और विशेष रूप से * आपके * फ़ंक्शन 'f' के भीतर से कुछ भी नहीं। –

+5

यह व्यर्थ होगा, क्योंकि मूल्य के आधार पर पॉइंटर को कैप्चर करना उतना ही खतरनाक है जितना संदर्भ को कैप्चर करना। –

+0

@BenVoigt यह सही है। – log0

उत्तर

5

एमएसल्टर्स नोट करते हैं कि "गैर-कैप्चरिंग लैम्ब्डा को पॉइंटर-टू-फ़ंक्शन में परिवर्तित किया जा सकता है।" इसका क्या मतलब है? लैम्ब्डा ऑब्जेक्ट फ़ंक्शन पैरामीटर प्रकार के लिए पॉइंटर से मेल खाता है।

लैम्ब्डा प्रकार को पॉइंटर-टू-फ़ंक्शन में अनुवाद करना मुश्किल है। एक अनुपालन कार्यान्वयन पर मेरा प्रयास यहां है। यह थोड़ा हैकिश है।

#include <type_traits> 

template< typename fn > 
struct ptmf_to_pf; 

template< typename r, typename c, typename ... a > 
struct ptmf_to_pf< r (c::*) (a ...) const > 
    { typedef r (* type)(a ...); }; 

// Use SFINAE to hide function if lambda is not convertible to function ptr. 
// Only check that the conversion is legal, it never actually occurs. 

template< typename lambda > 
typename std::enable_if< std::is_constructible< 
     typename ptmf_to_pf< decltype(&lambda::operator()) >::type, 
     lambda >::value >::type 
f(lambda arg) { 
    arg("hello "); 
    arg("world\n"); 
} 

#include <iostream> 

int main() { 
int x = 3; 
    f([](char const *s){ std::cout << s; }); // OK 
    f([=](char const *s){ std::cout << s; }); // OK 
    f([=](char const *s){ std::cout << s << x; }); // error 
} 

यह सीधा तर्क के रूप में कार्य संकेत को स्वीकार नहीं करेगा, क्योंकि टेम्पलेट पैरामीटर एक functor को हल करने की जरूरत है। आप इसे ptmf_to_pf के लिए विशेषज्ञता प्रदान करके ऐसा कर सकते हैं जो फ़ंक्शन प्रकारों के लिए पॉइंटर स्वीकार करता है।

इसके अलावा, जैसा कि डेमो दिखाता है, यह लैम्बडा स्वीकार नहीं करेगा जो मूल्य के साथ-साथ संदर्भ द्वारा कुछ भी कैप्चर करता है। प्रतिबंध को इतना विशिष्ट बनाने के लिए सी ++ में कोई रास्ता नहीं है।

+0

क्यों टेम्पलेट के बिना लम्बा को फ़ंक्शन पॉइंटर के रूप में पास नहीं करते हैं? – perreal

+1

@perreal: यदि आप वांछित फ़ंक्शन पॉइंटर प्रकार जानते हैं, तो ऐसा करें। सामान्य मामले में यह ज्ञात नहीं है। – Potatoswatter

5

शायद तुम लैम्ब्डा अभिव्यक्ति की कैप्चरिंग व्यवहार गलत समझ रहे हैं: एक बंद वस्तु है जैसे एक functor वस्तु से बताया है, इसलिए

struct Fun 
{ 
    Fun (int & a) : n(a) { } 
    int operator()(...) { ... } 
private: 
    int & n; 
}; 

int q; 
Fun f(q); 
f(...); 

बिल्कुल

int q; 
auto f = [&q](...) -> int { ... }; 
f(...); 
रूप में ही है

एक बार बंद ऑब्जेक्ट का निर्माण हो जाने के बाद, सभी कैप्चरिंग और बाध्यकारी समाप्त हो जाती है और ऑब्जेक्ट में हमेशा बंद हो जाती है।

यदि आप ऑब्जेक्ट को call_me(f) जैसे किसी अन्य स्थान पर पास करते हैं, तो प्राप्तकर्ता फ़ंक्शन का फ़ैक्टर या क्लोजर ऑब्जेक्ट के निर्माण से कोई संबंध नहीं है।

+1

यह सच है, लेकिन लैम्ब्डा के कंपाइलर-जेनरेट किए गए प्रकार में कैप्चर होने के बारे में सभी विवरण शामिल हैं। कोई आसानी से मेटाडेटा सिस्टम की कल्पना कर सकता है जिसने उस प्रकार के आत्मनिरीक्षण को यह देखने के लिए अनुमति दी कि क्या कोई संदर्भ सदस्य थे (या क्या निर्माता के पास कोई संदर्भ पैरामीटर है)। –

+0

@ बेनवोइग हां जो कि मज़ेदार वस्तु का गुण हो सकता है ... – log0

3

अप्रत्यक्ष हैक: केवल गैर-कैप्चरिंग लैम्ब्डा को पॉइंटर-टू-फ़ंक्शन में परिवर्तित किया जा सकता है। बेशक, इसमें F प्रकार भी शामिल हैं जो लैम्ब्डा नहीं हैं।

+0

गैर-लैम्ब्डा फ़ंक्शन पॉइंटर्स को अनुमति देना शायद हानिरहित या फायदेमंद है।+1 – Potatoswatter

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