2015-11-30 7 views
8

हर में कुछ अब कब्जा बनाम सब कुछ पर कब्जा करने के लिए और फिर मैं इस तरह कोड के साथ आते हैं:केवल एक लैम्ब्डा

// lazy lambda: 
[&] { 
// use references to a, b, c 
} 

// pedantic lambda 
[&a, &b, &c] { 
// use references to a, b, c 
} 

मुझे पता है कि जो lambdas के प्रदर्शन और शायद के मामले में बेहतर है करना चाहते हैं निष्पादन योग्य आकार सी ++ 14 मानक (या बाद में) और कंपाइलर्स के साथ आपके व्यावहारिक अनुभव के अनुसार।

+0

यदि आलसी लैम्ब्डा पैडेंटिक लैम्ब्डा के समान चर को कैप्चर करने के समाप्त होता है, तो मुझे कोई कारण नहीं दिखता कि प्रदर्शन या यहां तक ​​कि जेनरेट किए गए मशीन कोड अलग-अलग क्यों हो सकते हैं। – alain

+2

आईडीके अगर मानक के लिए अनुमति है या नहीं, लेकिन मुझे लगता है कि कंपाइलर केवल आपके द्वारा उपयोग किए जाने वाले चर को कैप्चर करेगा। – NathanOliver

+3

अंतर पूरी तरह से वाक्य रचनात्मक है, अर्थपूर्ण नहीं। दोनों lambdas एक ही काम करते हैं। –

उत्तर

3

मामूली मामला को छोड़कर जहां आप स्पष्ट रूप से लैम्ब्डा में उल्लेख नहीं किया गया है, वहां दो कोने के मामले हैं जहां कोई अंतर हो सकता है।

सबसे पहले, निहित कैप्चर आम तौर पर उन इकाइयों को कैप्चर नहीं करते हैं जो odr-used नहीं हैं (लेकिन इसके अपवाद के लिए अगला आइटम देखें)। यह अन्य बातों के अलावा, भी शामिल है, इस तरह के decltype और sizeof, उन लोगों के रूप में unevaluated ऑपरेंड और साथ ही कुछ const और constexpr स्थानीय चर में वर्णित बातें जब कुछ संदर्भों में इस्तेमाल किया (नियमों का पूरा सेट के लिए [basic.def.odr] से परामर्श):

void f(int){} 
void f2(const int &) {} 
void t() { 
    const int x = 8; 
    constexpr double y = 8; 
    const double z = 8; 
    auto g = []{ f(x); }; // OK 
    auto g1 = [=]{ f(x); }; // OK, does not capture x 

    // usually won't fire, though not guaranteed 
    static_assert(sizeof(g) == sizeof(g1), "!!"); 

    auto g2 = []{ f(y); }; // OK 
    auto g3 = []{ f(z); }; // Error, must capture z 

    auto g4 = []{ f2(x); }; // Error, must capture x since it's odr-used 
    auto g5 = [=]{ f2(x); }; // OK, captures x 
    auto g6 = []{ f2(+x); }; // OK, doesn't odr-use x 
    auto g7 = []{ f2(y); }; // OK 
} 

यदि आप मैन्युअल रूप से कैप्चर सूची लिखते हैं, तो यह संभव है कि आप तकनीकी रूप से आवश्यकतानुसार अधिक कैप्चर करेंगे, क्योंकि नियमों का संचालन करने वाले नियमों को नियंत्रित करना बहुत जटिल है।

दूसरा, जेनेरिक लैम्बडास में अंतर्निहित कैप्चर एक निर्भर अभिव्यक्ति में उपयोग की जाने वाली चीजों को कैप्चर करेगा, भले ही वे अनिवार्य रूप से ओड-प्रयुक्त नहीं हैं, सैनिटी के लिए। an example from the standard उधार:

void f(int, const int (&)[2] = {}) { } // #1 
void f(const int&, const int (&)[1]) { } // #2 
void test() { 
    const int x = 17; 
    auto g2 = [=](auto a) { 
    int selector[sizeof(a) == 1 ? 1 : 2]{}; 
    f(x, selector); // OK: is a dependent expression, so captures x 
        // Will actually odr-use x only if sizeof(a) == 1 
    }; 
} 

हालांकि, अगर आप वास्तव में कुछ है कि हो सकता है या हो सकता है-नहीं-हो-ओडीआर से इस्तेमाल किया जब एक सामान्य लैम्ब्डा लेखन पर कब्जा करने की आवश्यकता नहीं है; आपको केवल इसे कैप्चर करने की आवश्यकता होती है यदि आप फ़ंक्शन कॉल ऑपरेटर की विशेषज्ञता को तुरंत चालू करते हैं जो ओडीआर-चीज का उपयोग करता है। और इसलिए यदि आप परिणामी जेनेरिक लैम्ब्डा को इस तरह से कभी भी कॉल नहीं करते हैं जो इस मुद्दे पर समस्या का उपयोग करेगा, तो निहित कैप्चर आपको आवश्यक न्यूनतम से अधिक कैप्चर कर सकता है। उदाहरण के लिए, इस अनुमति दी है:

void test() { 
    const int x = 17; 
    auto g3 = [](auto a) { // no capture 
    int selector[sizeof(a) == 1 ? 1 : 2]{}; 
    f(x, selector); // OK for now 
    }; 
} 

जब तक आप कुछ भी जिसका आकार 1 है साथ g3 फोन नहीं है: g3(0) ठेठ सिस्टम पर ठीक है, g3('\0') नहीं है।

5

इस उदाहरण में कोई अंतर नहीं है। कंपाइलर केवल उन चरों को कैप्चर करेगा जिन्हें स्पष्ट रूप से लैम्ब्डा में संदर्भित किया गया है, जो आलसी कैप्चर को स्पष्ट के बराबर बनाते हैं।

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

1

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

मुझे विश्वास है कि 'आलसी कैप्चरिंग' बिल्कुल अच्छी सुविधा नहीं है।

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