2010-05-30 23 views
53

मैंने इंटरनेट पर कई ट्यूटोरियल पढ़े हैं जो मानक लाइब्रेरी (जैसे std::find) के साथ लैम्ब्स का उपयोग करने के तरीके को समझाते हैं, और वे सभी बहुत ही रोचक थे, लेकिन मुझे यह नहीं मिला कि मैं अपने आप के लिए लैम्ब्डा का उपयोग कैसे कर सकता हूं कार्य करता है।लैम्बडा स्वीकार करने वाले फ़ंक्शन को कैसे घोषित करें?

उदाहरण के लिए:

int main() 
{ 
    int test = 5; 
    LambdaTest([&](int a) { test += a; }); 

    return EXIT_SUCCESS; 
} 

मैं कैसे LambdaTest घोषित करना चाहिए? इसका पहला तर्क किस प्रकार का है? और फिर, मैं इसे गुजरने वाले अज्ञात फ़ंक्शन को कैसे कॉल कर सकता हूं - उदाहरण के लिए - "10" इसकी तर्क के रूप में?

उत्तर

51

यह देखते हुए कि आप शायद लैम्बडास के अलावा फ़ंक्शन पॉइंटर्स और फ़ंक्शन ऑब्जेक्ट्स भी स्वीकार करना चाहते हैं, तो आप शायद operator() के साथ किसी भी तर्क को स्वीकार करने के लिए टेम्पलेट का उपयोग करना चाहेंगे। यह वही है जो std-functions खोज करते हैं। यह इस तरह दिखेगा:

template<typename Func> 
void LambdaTest(Func f) { 
    f(10); 
} 

ध्यान दें कि यह परिभाषा किसी C++ 0x सुविधाओं का उपयोग नहीं करता है, तो यह पूरी तरह से पीछे की ओर संगत है। यह केवल lambda अभिव्यक्तियों का उपयोग करके फ़ंक्शन को कॉल करता है जो C++ 0x-specific है।

+0

यह सबसे अच्छा जवाब है। – Puppy

+2

त्रुटियों के मामले में त्रुटि संदेशों को समझना मुश्किल होगा। – liori

+13

यह निर्भर करता है कि यह सबसे अच्छा है या नहीं। यह एक टेम्पलेट का उपयोग करता है, और दूसरा नहीं करता है। इसका मतलब है कि फ़ंक्शन अब वर्चुअल नहीं हो सकता है और सीपीपी फ़ाइल में अलग से परिभाषित नहीं किया जा सकता है। 'std :: function' पूरी तरह से फ़ंक्शन ऑब्जेक्ट क्लास प्रकारों को लेने में सक्षम है, यद्यपि कॉल करते समय थोड़ा धीमा है। लेकिन यह अंतर बहुत अधिक अनुप्रयोगों के लिए नगण्य है :) –

53

तुम सब कुछ टेम्पलेट नहीं करना चाहते हैं, तो आप निम्न कर सकते हैं:

void LambdaTest (const std::function <void (int)>& f) 
{ 
    ... 
} 
+1

यह वाक्यविन्यास वास्तव में मुझे फ़ंक्शन वैरिएबल को बाद में कॉल करने के लिए सहेजने की अनुमति देता है, है ना? उदाहरण के लिए, मैं एक फ़ंक्शन को कार्यान्वित करना चाहता था जो एसिंक्रोनस डेटाबेस क्वेरीज़ निष्पादित करने की अनुमति देता है, जहां लैम्ब्डा कॉलबैक के रूप में कार्य करता है। (बेशक मैं संदर्भ द्वारा बंद करने में सक्षम नहीं होगा) –

+1

क्या मूल्य से कार्य पास करने के लिए यह अधिक मूर्ख नहीं है? – fredoverflow

+1

@Andreas Bonini: हाँ, अगर आप 'std :: function' (संदर्भ नहीं) में सहेजते हैं, तो आप 'f' की एक प्रति बनाते हैं। हालांकि, मुझे यकीन नहीं है कि कैसे लैम्ब्डा/क्लोजर संदर्भों को संभालते हैं जब ऑब्जेक्ट का उल्लेख गुंजाइश से बाहर हो जाता है, शायद यूबी। @FredOverflow: मेरी समझ यह है कि 'std :: function' एक छोटी वस्तु नहीं है, खासकर जब भेड़ के बच्चे को लपेटते हैं। अनावश्यक प्रतिलिपि से बचने के लिए इसका संदर्भ देना शायद बेहतर है। – doublep

4

मैं इस सरल लेकिन आत्म व्याख्यात्मक उदाहरण योगदान करना चाहते हैं। यह दिखाता है कि "कॉल करने योग्य चीजें" (फ़ंक्शंस, फ़ंक्शन ऑब्जेक्ट्स, और लैम्बडास) को फ़ंक्शन या किसी ऑब्जेक्ट में कैसे पास किया जाए।

// g++ -std=c++11 thisFile.cpp 

#include <iostream> 
#include <thread> 

using namespace std; 

// ----------------------------------------------------------------- 
class Box { 
public: 
    function<void(string)> theFunction; 
    bool funValid; 

    Box() : funValid (false) { } 

    void setFun (function<void(string)> f) { 
    theFunction = f; 
    funValid = true; 
    } 

    void callIt() { 
    if (! funValid) return; 
    theFunction (" hello from Box "); 
    } 
}; // class 

// ----------------------------------------------------------------- 
class FunClass { 
public: 
    string msg; 
    FunClass (string m) : msg (m) { } 
    void operator() (string s) { 
    cout << msg << s << endl; 
    } 
}; 

// ----------------------------------------------------------------- 
void f (string s) { 
    cout << s << endl; 
} //() 

// ----------------------------------------------------------------- 
void call_it (void (*pf) (string)) { 
    pf("call_it: hello"); 
} //() 

// ----------------------------------------------------------------- 
void call_it1 (function<void(string)> pf) { 
    pf("call_it1: hello"); 
} //() 

// ----------------------------------------------------------------- 
int main() { 

    int a = 1234; 

    FunClass fc (" christmas "); 

    f("hello"); 

    call_it (f); 

    call_it1 (f); 

    // conversion ERROR: call_it ([&] (string s) -> void { cout << s << a << endl; }); 

    call_it1 ([&] (string s) -> void { cout << s << a << endl; }); 

    Box ca; 

    ca.callIt(); 

    ca.setFun (f); 

    ca.callIt(); 

    ca.setFun ([&] (string s) -> void { cout << s << a << endl; }); 

    ca.callIt(); 

    ca.setFun (fc); 

    ca.callIt(); 

} //() 
+2

में इसे पारित करने के लिए कोई बिंदु नहीं है, आपको मज़ेदार की आवश्यकता नहीं है: http://en.cppreference.com/w/cpp/utility/functional/function/operator_bool, बस कहें 'अगर (! समारोह) ' –

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