एक लंबर को स्वीकार करने वाले फ़ंक्शन की घोषणा कैसे करें?


83

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

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

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

    return EXIT_SUCCESS;
}

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

जवाबों:


80

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

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

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


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

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

3
"सबसे अच्छा" देखने वाले की नज़र में है :-) यह उत्तर एक functorअच्छा उपयोग करता है , लेकिन वास्तव में मूल प्रश्न का उत्तर नहीं देता है (और मुझे यहाँ क्यों लाया गया) जो था "मैं अपने कार्यों के लिए एक लैम्ब्डा का उपयोग कैसे करता हूं" । इसके अलावा, टेम्प्लेट के पास मुद्दों का अपना सेट होता है, जिसका उत्तर std::functionनहीं होता है।
मार्को मासेंज़ियो

2
@ मार्को इस उत्तर के लिए आपको फंक्शनल का उपयोग करने की आवश्यकता नहीं है, यह आपको लैम्ब्डा सहित - जो भी आप चाहते हैं, का उपयोग करने की अनुमति देता है।
sepp2k

73

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

#include<functional> 

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

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

1
क्या मूल्य से कार्यों को पारित करना अधिक मुहावरेदार नहीं है?
फ्रेडोवरफ्लो

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

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

1
हमें इसे फ़ंक्शन के अंदर कॉपी करना होगा, इसलिए इसे कॉपी करने का कोई मतलब नहीं है क्योंकि इसे पास किया गया है
केसबैश

9

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

// 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
आपको funValid की आवश्यकता नहीं है: en.cppreference.com/w/cpp/utility/functional/function/… , बस इतना ही कहना हैif ( ! theFunction )
Erik Aronesty
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.