2012-05-23 12 views
12

सी ++ 11 में पैरामीटर/स्टोरेज प्रकार, आप एक फ़ंक्शन घोषित करते हैं जो लैम्बडा अभिव्यक्ति को तर्क के रूप में लेता है? मुझे लैम्ब्डा घोषित करने या उन्हें टेम्पलेट पैरामीटर के रूप में लेने के लिए ऑनलाइन संसाधनों का बहुत कुछ मिल सकता है, लेकिन मैं वास्तव में क्या करना चाहता हूं, यह लैम्बडास को कॉलबैक हैंडलर को आसानी से घोषित करने में सक्षम है, जो बंद होने से संभव हो गया है जावास्क्रिप्ट में और उद्देश्य-सी में कोड ब्लॉक।सी ++ 11 लैम्ब्डा

class MyCallback { 
public: 
    virtual ~MyCallback() {} 
    virtual void operator(int arg) = 0; 
}; 

void registerCallback(const std::shared_ptr<MyCallback> &); 

void foo(void) { 
    int a, b, c; 
    class LocalCallback: public MyCallback { 
     int a, b, c; 
    public: 
     LocalCallback(int a, int b, int c): a(a), b(b), c(c) {} 
     void operator(int arg) { std::cout << (a+b+c)*arg << std::endl; } 
    }; 
    registerCallback(std::shared_ptr<MyCallback>(new LocalCallback(a,b,c))); 
} 

जिसमें सरलीकृत किया जाएगा:

void registerCallback(/* WHAT GOES HERE? */); 

void foo(void) { 
    int a, b, c; 
    registerCallback([=](int arg){std::cout << (a+b+c)*arg << std::endl; }) 
} 

तो, जहाँ मैं /* WHAT GOES HERE? */ जो लिखा है उसे हो जाता है

अनिवार्य रूप से, क्लासिक सी ++ का निर्माण मैं एक लैम्ब्डा के साथ बदलना चाहते हैं कुछ की तरह है ?

संपादित करें: यह तुरंत कॉल करने और कॉल करने के बजाए कॉलबैक को स्टोर करने के उद्देश्य से वापस कॉल करने के उद्देश्य से है।

+0

स्थानीय प्रकारों का उपयोग टेम्पलेट तर्कों के रूप में C++ 03 में कानूनी नहीं है। कुछ कंपाइलर इसे एक विस्तार के रूप में अनुमति देते हैं। – bames53

+2

लैम्ब्डा का लाभ यह है कि यह कॉलबैक लिखना आसान बनाता है। आप विशेष रूप से कोड नहीं लिखते हैं जिसका प्रयोग लैम्बडास के साथ किया जाएगा, आप केवल कोड लिखेंगे जो 'फ़ंक्शन' तर्क लेगा और कॉलर लैम्बडा का उपयोग (या नहीं) कर सकता है। –

+0

@ barnes53 मेरे द्वारा पोस्ट किया गया कोड स्थानीय प्रकारों को टेम्पलेट तर्क के रूप में उपयोग नहीं करता है। MyCallback एक वैश्विक है, और स्थानीय प्रकार std :: shared_ptr में लपेटा जा रहा है। मैं हर समय काम पर इस पैटर्न का उपयोग करता हूं, यही कारण है कि मुझे सी ++ 11 के तरीके में दिलचस्पी है। :) – fluffy

उत्तर

20

आमतौर पर const std::function<void(int)> & या std::function<void(int)>

मुझे यकीन नहीं है कि std::function पर निर्णय क्या है या नहीं, इसके आधार पर निर्णय क्या है। शायद मूल्य से ठीक है, खासकर जब से आप स्टोर करने के लिए इसे कॉपी करने जा रहे हैं।

यदि यह सभी वाक्यविन्यास के बीच में स्पष्ट नहीं है, तो void(int) एक फ़ंक्शन प्रकार है, और std::function<T> का अर्थ है, "टाइप टी के कार्यों के समान हस्ताक्षर वाला एक फ़ैक्टर"।

लैम्बडास में अज्ञात प्रकार हैं। कोई रास्ता नहीं है अपने लैम्ब्डा अभिव्यक्ति के प्रकार के नाम के लिए नहीं है, और एक ही हस्ताक्षर के साथ अलग अलग लैम्ब्डा भाव के प्रकार से अलग हैं:

auto foo = [=](int arg){std::cout << (a+b+c)*arg << std::endl; }; 
auto bar = [=](int arg){std::cout << (a+b+c)*arg << std::endl; }; 
// foo and bar have different types, accessible as decltype(foo), decltype(bar) 
इसलिए

std::function, जो मूल रूप से इकट्ठा करने के लिए एक प्रकार-मिटाकर आवरण है के लिए की जरूरत एक ही प्रकार के समान हस्ताक्षर के साथ एक साथ विभिन्न मज़ेदार। यह टेम्पलेट्स के साथ स्थैतिक बहुरूपता के बीच का पुल है, और यदि आप कॉलबैक पंजीकृत करना चाहते हैं तो गतिशील बहुरूपता की आवश्यकता है, इसे बाद में स्टोर करें, और उसके बाद मूल प्रकार को "याद" किए बिना कॉल करें।

+0

धन्यवाद। जैसा कि सामान्य है, मैं अपने प्रश्न पोस्ट करने के बाद लगभग 30 सेकंड में std :: फ़ंक्शन में आया, लेकिन आपका उत्तर जो मैंने लिखा होगा उससे बेहतर है। इसे 'decltype()' सामान के लिए भी स्वीकार करना और सी ++ 11 में लैम्बडा और फ़ंक्शन-प्रकार कैसे काम करते हैं, इस बारे में पूर्ण स्पष्टीकरण। (या, जब मैं SO को देता हूं तो मैं इसे स्वीकार करूंगा ...) – fluffy

7
void registerCallback(const std::function<void(int)>& callback); 
5

फ़ंक्शन टेम्पलेट का उपयोग करने पर विचार करें। (नहीं भी महत्वपूर्ण तुम भी Functor functor के रूप में पैरामीटर स्वीकार कर सकते हैं, कि।)

template<typename Functor> 
void registerCallback(Functor&& functor); 

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

+0

क्या यह आवश्यक नहीं है कि कार्यान्वयन को किसी भी चीज़ के लिए दृश्यमान रखा जाए (यानी हेडर फ़ाइल में)? या सी ++ 11 आखिर में templatized विधियों के कार्यान्वयन विवरण छुपा रखने में सक्षम है? – fluffy

+0

@fluffy: हाँ, यह आवश्यकता सच है। लेकिन क्या वास्तव में कोई फर्क पड़ता है? – ildjarn

+0

@ildjarn यह करता है कि अगर मैं किसी सार्वजनिक हेडर फ़ाइल में कार्यान्वयन का खुलासा नहीं करना चाहता, या यदि मैं इसे इंटरफ़ेस पर वर्चुअल विधि बनाना चाहता हूं, तो साझा पुस्तकालयों और अन्य परिस्थितियों के साथ अन्य सभी एज स्थितियों का उल्लेख न करें templatized तरीकों बस सादा काम नहीं करते हैं। – fluffy