एक लंबोदर अभिव्यक्ति लौटाने का कार्य


88

मुझे आश्चर्य है कि अगर यह एक फ़ंक्शन लिखना संभव है जो C ++ 11 में एक लंबा फ़ंक्शन देता है। बेशक एक समस्या यह है कि इस तरह के फ़ंक्शन को कैसे घोषित किया जाए। प्रत्येक लंबोदर का एक प्रकार है, लेकिन वह प्रकार C ++ में स्पष्ट नहीं है। मुझे नहीं लगता कि यह काम करेगा:

auto retFun() -> decltype ([](int x) -> int)
{
    return [](int x) { return x; }
}

और न ही यह:

int(int) retFun();

मैं लंबों से किसी भी स्वचालित रूपांतरण के बारे में नहीं जानता हूँ, कहते हैं, कार्यों के लिए संकेत, या कुछ ऐसे। क्या एकमात्र समाधान एक फ़ंक्शन ऑब्जेक्ट को सौंपना और उसे वापस करना है?


1
जोड़ने के लिए जो पहले से ही कहा गया है, स्टेटलेस लैम्ब्डा फ़ंक्शन फ़ंक्शन पॉइंटर्स के लिए परिवर्तनीय हैं।
snk_kid

3
IMO आपका पहला विकल्प कार्य नहीं करेगा क्योंकि decltype
लंबोदर

1
वैसे, अगर एक लैम्ब्डा के पास एक खाली कैप्चर क्लॉज है, तो यह कार्य करने के लिए एक पॉइंटर के समान रूप से परिवर्तनीय हो सकता है।
GManNickG

@ मन: जब तक आप विजुअल C ++ 2010 या g ++ का एक संस्करण जारी कर रहे हैं, जो लगभग एक साल पहले (या उसके बाद) से अधिक जारी है। N3092 में मार्च 2010 तक कैप्चरलेस-लैंबडा फंक्शन पॉइंटर पॉवर्टर में जोड़ा नहीं गया था।
जेम्स मैकनेलिस

4
सामान्य रूप से लंबित ऑपरेंड में लैम्ब्डा के भाव प्रकट नहीं हो सकते हैं। तो decltype([](){})या sizeof([]() {})कोई बात नहीं, जहां आप इसे लिखते हैं, बीमार है।
जोहान्स शाउब -

जवाबों:


98

आपको एक दस्तकारी फ़ंक्शन ऑब्जेक्ट की आवश्यकता नहीं है, बस उपयोग करें std::function, जिसके लिए लैम्ब्डा फ़ंक्शन परिवर्तनीय हैं:

यह उदाहरण पूर्णांक पहचान फ़ंक्शन लौटाता है:

std::function<int (int)> retFun() {
    return [](int x) { return x; };
}

6
ओह! मैं StackOverflow प्यार करता हूँ। मुझे इस विषय पर शोध करने में बहुत समय लगा होगा, फिर स्टैकऑवरफ्लो पर जवाब मिलेगा। धन्यवाद शॉन!
बार्टोज़ मिलवस्की

6
यह हालांकि के निर्माण में एक स्मृति आवंटन का कारण बनने जा रहा है std::function
मैक्सिम इगोरुशिन

2
@Maxim Yegorushkin std :: फ़ंक्शन ने शब्दार्थ विज्ञान को स्थानांतरित कर दिया है और साथ ही यह कस्टम एलोकेटर्स का उपयोग कर सकता है और C ++ 0x वर्किंग ड्राफ्ट में ये नोट हैं: "[नोट: कार्यान्वयन को प्रोत्साहित किया जाता है ताकि छोटे कॉलगर्ल ऑब्जेक्ट्स के लिए गतिशील रूप से आवंटित मेमोरी के उपयोग से बचें , जहां f का लक्ष्य केवल ऑब्जेक्ट या पॉइंटर का संदर्भ रखने वाला ऑब्जेक्ट है और सदस्य फ़ंक्शन पॉइंटर है। - ध्यान दें] "तो मूल रूप से आप यह अनुमान नहीं लगा सकते हैं कि एक विशेष कार्यान्वयन किस रणनीति का उपयोग कर रहा है लेकिन आपको सक्षम होना चाहिए। वैसे भी अपने (पूल किए गए) आवंटनकर्ताओं का उपयोग करने के लिए।
snk_kid

1
@ मैक्सिम: मेरा जवाब इस सवाल पर था कि "क्या एकमात्र समाधान एक फ़ंक्शन ऑब्जेक्ट को हैंडीक्राफ्ट कर रहा है और इसे वापस कर रहा है?"
सीन

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

29

इस सरल उदाहरण के लिए, आपको आवश्यकता नहीं है std::function

मानक से §5.1.2 / 6:

एक के लिए बंद करने के प्रकार लैम्ब्डा अभिव्यक्ति कोई साथ लैम्ब्डा पर कब्जा एक सार्वजनिक गैर आभासी गैर स्पष्ट स्थिरांक रूपांतरण सूचक को कार्य करने के लिए बंद करने के प्रकार के समारोह कॉल ऑपरेटर के रूप में एक ही पैरामीटर और बदले प्रकार होने समारोह है। इस रूपांतरण फ़ंक्शन द्वारा लौटाया गया मान किसी फ़ंक्शन का पता होगा, जिसे लागू करते समय, क्लोजर प्रकार के फ़ंक्शन कॉल ऑपरेटर को लागू करने के समान प्रभाव पड़ता है।

क्योंकि आपके फ़ंक्शन में कैप्चर नहीं है, इसका मतलब है कि लंबोदर को पॉइंटर में बदलकर फंक्शन टाइप किया जा सकता है int (*)(int):

typedef int (*identity_t)(int); // works with gcc
identity_t retFun() { 
  return [](int x) { return x; };
}

यह मेरी समझ है, अगर मैं गलत हूं तो मुझे सुधारो।


1
यह सही लगता है। दुर्भाग्य से, यह मेरे द्वारा उपयोग किए जा रहे वर्तमान संकलक के साथ काम नहीं करता है: वीएस 2010। एसटीडी :: फ़ंक्शन रूपांतरण कार्य करने के लिए होता है।
बार्टोज़ मिल्वेस्की

3
हाँ, इस नियम का अंतिम शब्द VC2010 के लिए बहुत देर से आया।
बेन वोइगट

मैंने कोड उदाहरण जोड़ा है। यहाँ एक पूर्ण कार्यक्रम है
jfs

@JFSebastian - इस उदाहरण में मेमने का जीवनकाल क्या है? क्या यह फ़ंक्शन पॉइंटर में रूपांतरण के परिणाम को लंबा करने के लिए पर्याप्त है?
फ्लेक्सो

1
: - @JFSebastian मैं तो मैं अपने आप में एक सवाल के रूप में यह कहा है कि का उत्तर नहीं मिलता नहीं कर पा रहे stackoverflow.com/questions/8026170/...
Flexo

21

आप लैम्बडा फ़ंक्शन को अन्य लैम्बडा फ़ंक्शन से वापस कर सकते हैं, क्योंकि आपको स्पष्ट रूप से लैम्बडा फ़ंक्शन के रिटर्न प्रकार को निर्दिष्ट नहीं करना चाहिए। वैश्विक दायरे में ऐसा कुछ लिखें:

 auto retFun = []() {
     return [](int x) {return x;};
 };

2
यह केवल सच है जब बाहरी लैंबडा में सिर्फ रिटर्न स्टेटमेंट होता है। अन्यथा आपको रिटर्न प्रकार निर्दिष्ट करना होगा।
बार्टोज़ मिल्वस्की

3
यह सबसे अच्छा जवाब है क्योंकि इसमें std :: function के रनटाइम पॉलिमोर्फिज्म की आवश्यकता नहीं होती है और लैम्ब्डा के लिए एक गैर-खाली कैप्चर लिस्ट रखने की अनुमति देता है, हालाँकि मैं कॉन्स्ट ऑटो मस्ती का इस्तेमाल करता हूँ ...
robson3.14

2
CB 14 के बाद से @BartoszMilewski सच नहीं है।
dzhioev

19

हालाँकि यह प्रश्न विशेष रूप से C ++ 11 के बारे में पूछता है, अन्य लोगों के लिए जो इस पर ठोकर खाते हैं और C ++ 14 संकलक तक पहुंचते हैं, C ++ 14 अब साधारण कार्यों के लिए घटाए गए रिटर्न प्रकारों की अनुमति देता है। तो सवाल में उदाहरण को समायोजित करने के लिए बस के रूप में वांछित काम करने के लिए समायोजित किया जा सकता है -> decltype... समारोह पैरामीटर सूची के बाद खंड:

auto retFun()
{
    return [](int x) { return x; }
}

ध्यान दें, हालांकि, यह काम नहीं करेगा यदि return <lambda>;फ़ंक्शन में एक से अधिक दिखाई दें। ऐसा इसलिए है क्योंकि रिटर्न प्रकार कटौती पर प्रतिबंध यह है कि सभी रिटर्न स्टेटमेंट्स को एक ही प्रकार के एक्सप्रेशन वापस करने होंगे, लेकिन हर लैम्ब्डा ऑब्जेक्ट को कंपाइलर द्वारा अपना यूनीक टाइप दिया जाता है, इसलिए return <lambda>;हर एक का टाइप अलग होगा।


4
C ++ 14 के कम किए गए प्रकारों का उल्लेख क्यों करते हैं लेकिन बहुरूपता वाले लंबोधों का उल्लेख करते हैं? auto retFun() { return [](auto const& x) { return x; }; }
सेह

1

आपको इस तरह लिखना चाहिए:

auto returnFunction = [](int x){
    return [&x](){
        return x;
    }();
};

एक समारोह के रूप में अपनी वापसी पाने के लिए, और इसका उपयोग करें:

int val = returnFunction(someNumber);

0

यदि आपके पास c ++ 11 नहीं है और उदाहरण के लिए अपने c ++ कोड को माइक्रो कंट्रोलर पर चला रहे हैं। आप एक शून्य पॉइंटर लौटा सकते हैं और फिर एक कास्ट कर सकते हैं।

void* functionThatReturnsLambda()
{
    void(*someMethod)();

    // your lambda
    someMethod = []() {

        // code of lambda

    };

    return someMethod;
}


int main(int argc, char* argv[])
{

    void* myLambdaRaw = functionThatReturnsLambda();

    // cast it
    auto myLambda = (void(*)())myLambdaRaw;

    // execute lambda
    myLambda();
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.