क्या हम C ++ में फ़ंक्शन के अंदर कार्य कर सकते हैं?


226

मेरा मतलब कुछ इस तरह है:

int main() 
{
  void a() 
  {
      // code
  }
  a();

  return 0;
}

1
आप ऐसा करने की कोशिश क्यों कर रहे हैं? अपने उद्देश्य की व्याख्या करने से कोई व्यक्ति आपको अपने लक्ष्य को प्राप्त करने का सही तरीका बता सकता है।
थॉमस ओवंस

3
gcc गैर-मानक एक्सटेंशन के रूप में नेस्टेड फ़ंक्शंस का समर्थन करता है । लेकिन अगर आप gcc का उपयोग कर रहे हैं तो भी इसका बेहतर उपयोग न करें। और C ++ मोड में, यह वैसे भी उपलब्ध नहीं है।
स्वेन मार्नाच

27
@ थोमस: क्योंकि ए के दायरे को कम करना अच्छा होगा? फ़ंक्शंस में कार्य अन्य भाषाओं में एक सामान्य विशेषता है।
जोहान कोटलिंस्की

64
वह नेस्टेड कार्यों के बारे में बात कर रहा है। इसी तरह कक्षाओं के अंदर अगली कक्षाओं के लिए सक्षम होने के नाते, वह एक फ़ंक्शन के अंदर एक फ़ंक्शन को घोंसला बनाना चाहता है। वास्तव में, मेरे पास ऐसी परिस्थितियां हैं जहां मैंने ऐसा किया होगा, अगर यह संभव था, तो भी। ऐसी भाषाएं हैं (उदाहरण F #) जो इसे अनुमति देती है, और मैं आपको बता सकता हूं कि यह दर्जनों सहायक कार्यों के साथ एक पुस्तकालय को प्रदूषित किए बिना कोड को अधिक स्पष्ट, पठनीय और बनाए रख सकता है जो एक बहुत ही विशिष्ट संदर्भ के बाहर बेकार हैं। ;)
मफ्फेन

16
@Thomas - नेस्टेड फ़ंक्शंस बिना मौजूदा स्कोप को भरने के बिना जटिल फ़ंक्शंस / एल्गोरिदम को तोड़ने के लिए एक उत्कृष्ट तंत्र हो सकता है जो एन्क्लोज़िंग स्कोप के भीतर सामान्य उपयोग के नहीं हैं । पास्कल और एडा को उनके लिए सुंदर समर्थन मिला है। स्काला और कई अन्य पुरानी / नई सम्मानित भाषाओं के साथ भी। किसी भी अन्य विशेषता की तरह, उनका भी दुरुपयोग किया जा सकता है, लेकिन यह डेवलपर का एक कार्य है। IMO, वे अधिक लाभकारी रहे हैं जो हानिकारक है।
luis.espinal

जवाबों:


272

आधुनिक सी ++ - हां लंबोदर के साथ!

C ++ (C ++ 11, C ++ 14, और C ++ 17) के वर्तमान संस्करणों में, आप एक लंबोदर के रूप में कार्यों के अंदर कार्य कर सकते हैं:

int main() {
    // This declares a lambda, which can be called just like a function
    auto print_message = [](std::string message) 
    { 
        std::cout << message << "\n"; 
    };

    // Prints "Hello!" 10 times
    for(int i = 0; i < 10; i++) {
        print_message("Hello!"); 
    }
}

लैंबदास ** कैद-दर-संदर्भ * के माध्यम से स्थानीय चर भी संशोधित कर सकते हैं। कैप्चर-बाय-रेफरेंस के साथ, लैम्ब्डा की लैम्बडा के दायरे में घोषित सभी स्थानीय चर तक पहुंच है। यह उन्हें सामान्य रूप से संशोधित और बदल सकता है।

int main() {
    int i = 0;
    // Captures i by reference; increments it by one
    auto addOne = [&] () {
        i++; 
    };

    while(i < 10) {
        addOne(); //Add 1 to i
        std::cout << i << "\n";
    }
}

सी ++ 98 और सी ++ 03 - सीधे नहीं, लेकिन स्थानीय कक्षाओं के अंदर स्थिर कार्यों के साथ हां

C ++ सीधे समर्थन नहीं करता है।

उस ने कहा, आपके पास स्थानीय कक्षाएं हो सकती हैं, और उनके कार्य (गैर- staticया static) हो सकते हैं, इसलिए आप इसे कुछ हद तक प्राप्त कर सकते हैं, यद्यपि यह एक कीचड़ का एक सा है:

int main() // it's int, dammit!
{
  struct X { // struct's as good as class
    static void a()
    {
    }
  };

  X::a();

  return 0;
}

हालाँकि, मैं प्रैक्सिस पर सवाल उठाऊंगा। सभी जानते हैं (अच्छी तरह से, अब आप जो भी करते हैं :)) C ++ स्थानीय कार्यों का समर्थन नहीं करता है, इसलिए उनका उपयोग उनके नहीं होने के लिए किया जाता है। हालांकि, उनका उपयोग उस कीचड़ में नहीं किया जाता है। मैं यह सुनिश्चित करने के लिए इस कोड पर काफी समय खर्च करूंगा कि यह वास्तव में केवल स्थानीय कार्यों की अनुमति देने के लिए है। अच्छा नही।


3
यदि आप वापसी प्रकार के बारे में पंडित होने जा रहे हैं तो मुख्य भी दो आर्गन लेता है। :) (या यह वैकल्पिक है लेकिन इन दिनों वापसी नहीं है? मैं नहीं रख सकता।)
लियो डेविडसन

3
यह सिर्फ बुरा है - यह अच्छे, साफ कोड के हर सम्मेलन को तोड़ देता है। मैं एक भी उदाहरण के बारे में नहीं सोच सकता जहाँ यह एक अच्छा विचार है।
थॉमस ओवंस

19
@ थोमस ओवेन्स: यह अच्छा है अगर आपको कॉलबैक फ़ंक्शन की आवश्यकता है और इसके साथ कुछ अन्य नामस्थान को प्रदूषित नहीं करना चाहते हैं।
लियो डेविडसन

9
@ लियो: मानक कहते हैं कि मुख्य के लिए दो स्वीकार्य रूप हैं: int main()औरint main(int argc, char* argv[])
जॉन डिब्लिंग

8
मानक कहते हैं int main()और int main(int argc, char* argv[])समर्थित होना चाहिए और दूसरों का समर्थन किया जा सकता है, लेकिन वे सभी वापस लौट आए हैं।
जोज डे

261

सभी इरादों और उद्देश्यों के लिए, C ++ लैंबडास : 1 के माध्यम से इसका समर्थन करता है

int main() {
    auto f = []() { return 42; };
    std::cout << "f() = " << f() << std::endl;
}

यहाँ, fएक लैम्ब्डा ऑब्जेक्ट है जो एक स्थानीय फ़ंक्शन के रूप में कार्य करता है main। फ़ंक्शन को स्थानीय ऑब्जेक्ट तक पहुंचने की अनुमति देने के लिए कैप्चर निर्दिष्ट किया जा सकता है।

पर्दे के पीछे, fएक फंक्शन ऑब्जेक्ट (यानी एक प्रकार की वस्तु जो प्रदान करता है operator()) है। फ़ंक्शन ऑब्जेक्ट प्रकार को लंबर के आधार पर कंपाइलर द्वारा बनाया गया है।


C ++ 11 के बाद से 1


5
आह, यह साफ है! मैंने इसके बारे में नहीं सोचा था। यह मेरे विचार से बहुत बेहतर है, +1मुझसे।
sbi

1
@ एसबीआई: मैंने वास्तव में इसे अतीत में अनुकरण करने के लिए स्थानीय संरचनाओं का उपयोग किया है (हां, मैं अपने आप पर शर्मिंदा हूं)। लेकिन उपयोगिता इस तथ्य से सीमित है कि स्थानीय संरचनाएं बंद होने का निर्माण नहीं करती हैं, अर्थात आप उनमें स्थानीय चर का उपयोग नहीं कर सकते हैं। आपको एक कंस्ट्रक्टर के माध्यम से उन्हें स्पष्ट रूप से पारित करने और संग्रहीत करने की आवश्यकता है।
कोनराड रुडोल्फ

1
@Konrad: उनके साथ एक और समस्या यह है कि C ++ 98 में आपको स्थानीय प्रकार का टेम्पलेट पैरामीटर के रूप में उपयोग नहीं करना चाहिए। मुझे लगता है कि C ++ 1x ने हालांकि उस प्रतिबंध को हटा लिया है। (या वह C ++ 03 था?)
sbi

3
@ लुइस: मुझे फ्रेड के साथ सहमत होना चाहिए। आप एक अर्थ को लंबोदर से जोड़ रहे हैं जो उनके पास नहीं है (न तो सी ++ में और न ही अन्य भाषाओं में, जिनके साथ मैंने काम किया है - जिसमें रिकॉर्ड के लिए पायथन और एडा शामिल नहीं हैं)। इसके अलावा, यह भेद करना C ++ में सिर्फ सार्थक नहीं है क्योंकि C ++ में स्थानीय फ़ंक्शन, अवधि नहीं है। इसमें केवल लंबोदर हैं। यदि आप किसी फ़ंक्शन जैसी फ़ंक्शन की गुंजाइश को सीमित करना चाहते हैं, तो आपके एकमात्र विकल्प लैम्ब्डा या अन्य उत्तरों में उल्लिखित स्थानीय संरचना हैं। मैं कहूंगा कि बाद में किसी भी व्यावहारिक हित के लिए बहुत अधिक दृढ़ है।
कोनराड रुडोल्फ

2
@AustinWBryan नहीं, C ++ में लैम्ब्डा फंक्शंस के लिए सिंटैक्टिक शुगर है और इसमें शून्य ओवरहेड है। इस वेबसाइट पर कहीं अधिक विस्तार के साथ एक सवाल है।
कोनराड रुडोल्फ

43

स्थानीय कक्षाओं का उल्लेख पहले ही किया जा चुका है, लेकिन यहां एक ऑपरेटर () अधिभार और एक अनाम वर्ग का उपयोग करते हुए उन्हें स्थानीय कार्यों के रूप में प्रदर्शित करने का एक तरीका दिया गया है:

int main() {
    struct {
        unsigned int operator() (unsigned int val) const {
            return val<=1 ? 1 : val*(*this)(val-1);
        }
    } fac;

    std::cout << fac(5) << '\n';
}

मैं इसे इस्तेमाल करने की सलाह नहीं देता, यह सिर्फ एक मज़ेदार ट्रिक है (कर सकते हैं, लेकिन इमो नहीं होना चाहिए)।


2014 अपडेट:

कुछ समय पहले C ++ 11 के उदय के साथ, अब आपके पास स्थानीय कार्य हो सकते हैं जिनका वाक्यविन्यास जावास्क्रिप्ट की थोड़ी याद दिलाता है:

auto fac = [] (unsigned int val) {
    return val*42;
};

1
होना चाहिए operator () (unsigned int val), अपने गुम कोष्ठकों का एक सेट।
जो डी डी

1
वास्तव में, यह एक पूरी तरह से उचित बात है अगर आपको इस फंक्शनल को एक stl फ़ंक्शन या एल्गोरिथ्म को पास करने की आवश्यकता है, जैसे std::sort(), या std::for_each()
दीमा

1
@ दीमा: दुर्भाग्यवश, C ++ 03 में, स्थानीय रूप से परिभाषित प्रकारों का उपयोग टेम्पलेट तर्कों के रूप में नहीं किया जा सकता है। C ++ 0x इसे ठीक करता है, लेकिन लैम्ब्डा के बहुत अच्छे समाधान भी प्रदान करता है, इसलिए आप अभी भी ऐसा नहीं करेंगे।
बेन Voigt

उफ़, आप सही हैं। मेरी गलती। लेकिन फिर भी, यह सिर्फ एक मज़ेदार ट्रिक नहीं है। अगर इसकी अनुमति होती तो यह एक उपयोगी चीज होती। :)
दीमा

3
पुनरावृत्ति समर्थित है। हालाँकि, आप autoचर घोषित करने के लिए उपयोग नहीं कर सकते । स्ट्रॉस्ट्रुप उदाहरण देता है: function<void(char*b, char*e)> rev=[](char*b, char*e) { if( 1<e-b ) { swap( *b, *--e); rev(++b,e); } };एक स्ट्रिंग दी गई शुरुआत और अंत बिंदुओं को उलटने के लिए।
एपीस

17

नहीं।

तुम क्या करने की कोशिश कर रहे हो?

वैकल्पिक हल:

int main(void)
{
  struct foo
  {
    void operator()() { int a = 1; }
  };

  foo b;
  b(); // call the operator()

}

2
ध्यान दें कि क्लास इंस्टेंटिएशन अप्रोच एक मेमोरी एलोकेशन के साथ आता है और इसलिए यह स्टैटिक अप्रोच का वर्चस्व है।
मैनुअलसेलीन 3

14

C ++ 11 से शुरू करके आप उचित लैम्ब्डा का उपयोग कर सकते हैं । अधिक विवरण के लिए अन्य उत्तर देखें।


पुराना उत्तर: आप छांट सकते हैं, लेकिन आपको एक डमी क्लास को धोखा देना और उसका उपयोग करना है:

void moo()
{
    class dummy
    {
    public:
         static void a() { printf("I'm in a!\n"); }
    };

    dummy::a();
    dummy::a();
}

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

डमी से छुटकारा पाना :: अन्य उत्तरों में से एक है।
सेबस्टियन मच

8

जैसा कि दूसरों ने उल्लेख किया है, आप gcc में gnu भाषा एक्सटेंशन का उपयोग करके नेस्टेड फ़ंक्शन का उपयोग कर सकते हैं। यदि आप (या आपकी परियोजना) जीसीसी टूलचैन से चिपके रहते हैं, तो आपका कोड जीसीसी कंपाइलर द्वारा लक्षित विभिन्न आर्किटेक्चर के पार ज्यादातर पोर्टेबल होगा।

हालांकि, अगर कोई संभावित आवश्यकता है कि आपको एक अलग टूलकिन के साथ कोड संकलित करने की आवश्यकता हो सकती है, तो मैं ऐसे एक्सटेंशन से दूर रहूंगा।


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

लेकिन किसी भी चीज की तरह, वे दुरुपयोग के लिए खुले हो सकते हैं।

यह दुखद है कि C / C ++ मानक के रूप में ऐसी सुविधाओं का समर्थन नहीं करता है। अधिकांश पास्कल वेरिएंट और एडा करते हैं (लगभग सभी अल्गोल-आधारित भाषाएँ करते हैं)। जावास्क्रिप्ट के साथ भी। स्काला जैसी आधुनिक भाषाओं के साथ भी। Erlang, Lisp या Python जैसी आदरणीय भाषाओं के साथ भी।

और सी / सी ++ के साथ के रूप में, दुर्भाग्य से, जावा (जिसके साथ मैं अपने अधिकांश जीवित कमाता हूं) नहीं करता है।

मैं यहां जावा का उल्लेख करता हूं क्योंकि मैं कई पोस्टरों को कक्षाओं और कक्षा के तरीकों का उपयोग करने का सुझाव देता हूं ताकि नेस्टेड फ़ंक्शन के विकल्प के रूप में। और यह भी जावा में विशिष्ट समाधान है।

संक्षिप्त उत्तर: नहीं।

ऐसा करना एक वर्ग पदानुक्रम पर कृत्रिम, अनावश्यक जटिलता का परिचय देता है। सभी चीजें समान होने के साथ, आदर्श के लिए एक वास्तविक श्रेणी का प्रतिनिधित्व करते हुए एक वर्ग पदानुक्रम (और इसके नाम और स्कोप को शामिल करना) है।

नेस्टेड फ़ंक्शन "निजी" से निपटने में मदद करते हैं, फ़ंक्शन-फ़ंक्शन जटिलता के भीतर। उन सुविधाओं को कम करते हुए, किसी को उस "निजी" जटिलता को बाहर करने और किसी के क्लास मॉडल के प्रचार से बचने की कोशिश करनी चाहिए।

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


8

C ++ में आपके स्थानीय कार्य नहीं हो सकते। हालाँकि, C ++ 11 में लैम्ब्डा है । लैम्ब्डा मूल रूप से वैरिएबल होते हैं जो फ़ंक्शंस की तरह काम करते हैं।

एक लैम्ब्डा का प्रकार होता है std::function( वास्तव में यह बिल्कुल सच नहीं है , लेकिन ज्यादातर मामलों में आप मान सकते हैं कि यह है)। इस प्रकार का उपयोग करने के लिए, आपको करने की आवश्यकता है #include <functional>std::functionएक टेम्पलेट है, जो टेम्पलेट तर्क के रूप में रिटर्न प्रकार और तर्क प्रकार को सिंटैक्स के साथ लेता है std::function<ReturnType(ArgumentTypes)। उदाहरण के लिए, std::function<int(std::string, float)>एक लंबोदर एक लौट रहा है intऔर दो तर्क ले रहा है, एक std::stringऔर एक float। सबसे आम एक है std::function<void()>, जो कुछ भी नहीं लौटाता है और कोई तर्क नहीं लेता है।

एक बार एक लंबोदर घोषित होने के बाद, इसे सिंटैक्स का उपयोग करके सामान्य फ़ंक्शन की तरह कहा जाता है lambda(arguments)

एक लैम्ब्डा को परिभाषित करने के लिए, सिंटैक्स का उपयोग करें [captures](arguments){code}(इसे करने के अन्य तरीके हैं, लेकिन मैं यहां उनका उल्लेख नहीं करूंगा)। argumentsलैम्ब्डा क्या तर्क देता है, और codeवह कोड है जिसे लैम्ब्डा कहे जाने पर चलाया जाना चाहिए। आमतौर पर आप [=]या [&]कब्जा के रूप में डालते हैं । [=]इसका मतलब है कि आप उस मूल्य के दायरे में सभी चरों पर कब्जा कर लेते हैं, जिसका अर्थ मूल्य द्वारा परिभाषित किया गया है, जिसका अर्थ है कि वे उस मूल्य को रखेंगे जो उनके पास था जब लंबोदर घोषित किया गया था। [&]इसका मतलब है कि आप संदर्भ द्वारा सभी चर को दायरे में कैद कर लेते हैं, जिसका अर्थ है कि उनका हमेशा उनका वर्तमान मूल्य होगा, लेकिन यदि वे स्मृति से मिटा दिए जाते हैं, तो प्रोग्राम क्रैश हो जाएगा। यहाँ कुछ उदाहरण हैं:

#include <functional>
#include <iostream>

int main(){
    int x = 1;

    std::function<void()> lambda1 = [=](){
        std::cout << x << std::endl;
    };
    std::function<void()> lambda2 = [&](){
        std::cout << x << std::endl;
    };

    x = 2;
    lambda1();    //Prints 1 since that was the value of x when it was captured and x was captured by value with [=]
    lambda2();    //Prints 2 since that's the current value of x and x was captured by value with [&]

    std::function<void()> lambda3 = [](){}, lambda4 = [](){};    //I prefer to initialize these since calling an uninitialized lambda is undefined behavior.
                                                                 //[](){} is the empty lambda.

    {
        int y = 3;    //y will be deleted from the memory at the end of this scope
        lambda3 = [=](){
            std::cout << y << endl;
        };
        lambda4 = [&](){
            std::cout << y << endl;
        };
    }

    lambda3();    //Prints 3, since that's the value y had when it was captured

    lambda4();    //Causes the program to crash, since y was captured by reference and y doesn't exist anymore.
                  //This is a bit like if you had a pointer to y which now points nowhere because y has been deleted from the memory.
                  //This is why you should be careful when capturing by reference.

    return 0;
}

आप उनके नामों को निर्दिष्ट करके विशिष्ट चर भी पकड़ सकते हैं। केवल उनके नाम को निर्दिष्ट करने से वे मूल्य पर कब्जा कर लेंगे, उनके नाम को &पहले से निर्दिष्ट करके उन्हें संदर्भ द्वारा कैप्चर करेंगे। उदाहरण के लिए, [=, &foo]मूल्य के अलावा सभी चर पर कब्जा कर लेंगे , fooजिसे छोड़कर संदर्भ द्वारा कब्जा कर लिया [&, foo]जाएगा , और संदर्भ द्वारा सभी चर को पकड़ लेंगे , fooजिसके अलावा मूल्य पर कब्जा कर लिया जाएगा। तुम भी केवल विशिष्ट चरों पर कब्जा कर सकते हैं, उदाहरण के लिए [&foo]कब्जा fooसंदर्भ द्वारा और कोई अन्य चर पर कब्जा होगा। तुम भी उपयोग करके कोई चर पर कब्जा कर सकते हैं []। यदि आप एक लैम्ब्डा में वैरिएबल का उपयोग करने का प्रयास करते हैं जिसे आपने कैप्चर नहीं किया है, तो यह संकलित नहीं होगा। यहाँ एक उदाहरण है:

#include <functional>

int main(){
    int x = 4, y = 5;

    std::function<void(int)> myLambda = [y](int z){
        int xSquare = x * x;    //Compiler error because x wasn't captured
        int ySquare = y * y;    //OK because y was captured
        int zSquare = z * z;    //OK because z is an argument of the lambda
    };

    return 0;
}

आप एक वैरिएबल का मान नहीं बदल सकते हैं जो लैम्बडा के अंदर वैल्यू द्वारा कैप्चर किया गया था (वैल्यू द्वारा कैप्चर किए गए वेरिएबल constलैम्ब्डा के अंदर एक प्रकार है)। ऐसा करने के लिए, आपको संदर्भ द्वारा चर को पकड़ने की आवश्यकता है। यहाँ एक परीक्षा है:

#include <functional>

int main(){
    int x = 3, y = 5;
    std::function<void()> myLambda = [x, &y](){
        x = 2;    //Compiler error because x is captured by value and so it's of type const int inside the lambda
        y = 2;    //OK because y is captured by reference
    };
    x = 2;    //This is of course OK because we're not inside the lambda
    return 0;
}

इसके अलावा, बिन बुलाए लैम्ब्डा को कॉल करना अपरिभाषित व्यवहार है और आमतौर पर इस कार्यक्रम के दुर्घटनाग्रस्त होने का कारण होगा। उदाहरण के लिए, ऐसा कभी न करें:

std::function<void()> lambda;
lambda();    //Undefined behavior because lambda is uninitialized

उदाहरण

यहाँ लैम्बदास का उपयोग करके आप अपने प्रश्न में क्या करना चाहते हैं, इसके लिए कोड दिया गया है:

#include <functional>    //Don't forget this, otherwise you won't be able to use the std::function type

int main(){
    std::function<void()> a = [](){
        // code
    }
    a();
    return 0;
}

यहाँ एक मेमने का एक और अधिक उन्नत उदाहरण दिया गया है:

#include <functional>    //For std::function
#include <iostream>      //For std::cout

int main(){
    int x = 4;
    std::function<float(int)> divideByX = [x](int y){
        return (float)y / (float)x;    //x is a captured variable, y is an argument
    }
    std::cout << divideByX(3) << std::endl;    //Prints 0.75
    return 0;
}

7

नहीं, इसकी अनुमति नहीं है। डिफ़ॉल्ट रूप से न तो C और न ही C ++ इस सुविधा का समर्थन करता है, हालांकि टोनीके बताते हैं (टिप्पणियों में) कि GNU C संकलक के विस्तार हैं जो C में इस व्यवहार को सक्षम करते हैं।


2
यह एक विशेष विस्तार के रूप में जीएनयू सी कंपाइलर द्वारा समर्थित है। लेकिन केवल C के लिए, C ++ के लिए नहीं।
टोनीके

आह। मेरे C कंपाइलर में कोई विशेष एक्सटेंशन नहीं है। हालांकि यह जानना अच्छा है। मैं अपने जवाब में उस टाइटबिट को जोड़ दूंगा।
थॉमस ओवेन्स

मैंने नेस्टेड फ़ंक्शंस (सी में, हालांकि सी ++ नहीं) के समर्थन के लिए जीसीसी एक्सटेंशन का उपयोग किया है। नेस्टेड फ़ंक्शंस एक निफ्टी चीज़ हैं (जैसा कि पास्कल और एडा में) जटिल, फिर भी सामंजस्यपूर्ण संरचनाओं के प्रबंधन के लिए जो सामान्य उपयोग के लिए नहीं हैं। जब तक कोई gcc टूलचिन का उपयोग करता है, तब तक यह सभी लक्षित आर्किटेक्चर के लिए ज्यादातर पोर्टेबल होने का आश्वासन दिया जाता है । लेकिन अगर गैर-जीसी संकलक के साथ परिणामी कोड को संकलित करने का परिवर्तन होता है, तो, ऐसे एक्सटेंशन से बचने और एएनसी / पॉज़िक्स मंत्र के जितना करीब हो सके छड़ी करना सबसे अच्छा है।
luis.espinal

7

यह सभी तरकीबें स्थानीय कार्यों के रूप में (कमोबेश) दिखती हैं, लेकिन वे इस तरह काम नहीं करती हैं। एक स्थानीय फ़ंक्शन में आप इसके सुपर फ़ंक्शन के स्थानीय चर का उपयोग कर सकते हैं। यह एक तरह का सेमी-ग्लोबल्स है। इनमें से कोई भी ट्रिक ऐसा कर सकती है। निकटतम c ++ 0x से लैम्ब्डा ट्रिक है, लेकिन यह क्लोजर परिभाषा समय में बाध्य है, उपयोग समय नहीं है।


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

6

आप C ++ में दूसरे के अंदर एक मुफ्त फ़ंक्शन को परिभाषित नहीं कर सकते।


1
एएनएसआई / पॉज़िक्स के साथ नहीं, लेकिन आप ग्नू एक्सटेंशन के साथ कर सकते हैं।
luis.espinal

4

मुझे C ++ 03 के लिए यहां एक समाधान पोस्ट करने दें जिसे मैं सबसे साफ संभव मानता हूं। *

#define DECLARE_LAMBDA(NAME, RETURN_TYPE, FUNCTION) \
    struct { RETURN_TYPE operator () FUNCTION } NAME;

...

int main(){
  DECLARE_LAMBDA(demoLambda, void, (){ cout<<"I'm a lambda!"<<endl; });
  demoLambda();

  DECLARE_LAMBDA(plus, int, (int i, int j){
    return i+j;
  });
  cout << "plus(1,2)=" << plus(1,2) << endl;
  return 0;
}

(++) C ++ की दुनिया में मैक्रोज़ का उपयोग करना कभी भी साफ नहीं माना जाता है।


एलेक्सिस, आप यह कहना सही है कि यह पूरी तरह से साफ नहीं है। यह अभी भी साफ होने के करीब है क्योंकि यह अच्छी तरह से व्यक्त करता है कि प्रोग्रामर का क्या मतलब है, बिना साइड-इफेक्ट के। मुझे लगता है कि प्रोग्रामिंग की कला मानव-सहज रूप से अभिव्यंजक लिख रही है जो उपन्यास की तरह पढ़ती है।
बार्नी

2

लेकिन हम मुख्य के अंदर एक समारोह की घोषणा कर सकते हैं:

int main()
{
    void a();
}

हालाँकि सिंटैक्स सही है, कभी-कभी यह "मोस्ट वेस्टिंग पार्स" हो सकता है:

#include <iostream>


struct U
{
    U() : val(0) {}
    U(int val) : val(val) {}

    int val;
};

struct V
{
    V(U a, U b)
    {
        std::cout << "V(" << a.val << ", " << b.val << ");\n";
    }
    ~V()
    {
        std::cout << "~V();\n";
    }
};

int main()
{
    int five = 5;
    V v(U(five), U());
}

=> कोई प्रोग्राम आउटपुट नहीं।

(संकलन के बाद केवल क्लैंग चेतावनी)।

C ++ का सबसे अधिक अजीब पार्स

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