আমাদের কি সি ++ এর ভিতরে ফাংশন থাকতে পারে?


225

আমি এরকম কিছু বোঝাতে চাইছি:

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

  return 0;
}

1
আপনি কেন এটি করার চেষ্টা করছেন? আপনার উদ্দেশ্য ব্যাখ্যা করা আপনার কাউকে আপনার লক্ষ্য অর্জনের সঠিক উপায় বলার অনুমতি দিতে পারে।
থমাস 13

3
জিসিসি অ-মানক এক্সটেনশান হিসাবে নেস্টেড ফাংশনগুলিকে সমর্থন করে । তবে আপনি যদি সিসিসি ব্যবহার করে থাকেন তবে ভাল এটি ব্যবহার করবেন না। এবং সি ++ মোডে এটি কোনওভাবেই পাওয়া যায় না।
সোভেন মার্নাচ

27
@ থমাস: কারণ এটার পরিধি কমানো ভাল হবে? ফাংশনগুলিতে ফাংশনগুলি অন্যান্য ভাষার একটি সাধারণ বৈশিষ্ট্য।
জোহান কোটলিনস্কি

64
তিনি নেস্টেড ফাংশন সম্পর্কে কথা বলছেন। একইভাবে ক্লাসের ভিতরে পরবর্তী ক্লাসে সক্ষম হওয়ার জন্য, তিনি কোনও ফাংশনের ভিতরে কোনও ফাংশন বাসাতে চান। প্রকৃতপক্ষে, আমার যদি এমন পরিস্থিতি হয়েছিল যেখানে আমি এটি করতে পারতাম তবে এটিও সম্ভব হত। এখানে ভাষা রয়েছে (উদাহরণস্বরূপ F #) যা এটির অনুমতি দেয় এবং আমি আপনাকে বলতে পারি যে এটি একটি নির্দিষ্ট প্রসঙ্গের বাইরে অপ্রয়োজনীয় কয়েক ডজন সহায়ক ফাংশন সহ একটি লাইব্রেরিকে দূষিত না করে কোডটিকে আরও বেশি পরিষ্কার, পঠনযোগ্য এবং রক্ষণাবেক্ষণযোগ্য করে তুলতে পারে। ;)
মাফানে

16
@ থমাস - ঘেরাওনের ক্ষেত্রের মধ্যে সাধারণ ব্যবহারের নয় এমন ফাংশনগুলি দিয়ে বর্তমান সুযোগটি পূরণ না করেই জটিল ফাংশন / অ্যালগরিদম ভাঙ্গার জন্য নেস্টেড ফাংশনগুলি একটি দুর্দান্ত প্রক্রিয়া হতে পারে । পাস্কাল এবং অ্যাডা (আইএমও) তাদের জন্য সুন্দর সমর্থন করে। স্কালা এবং অন্যান্য অনেক পুরানো / নতুন সম্মানিত ভাষার সাথে একই। অন্য কোনও বৈশিষ্ট্যের মতো এগুলিও আপত্তিজনক হতে পারে তবে এটি বিকাশকারীর একটি কাজ। আইএমও, তারা ক্ষতির চেয়ে অনেক বেশি উপকারী হয়েছে।
luis.espinal

উত্তর:


271

আধুনিক সি ++ - হ্যাঁ ল্যাম্বডাসের সাথে!

সি ++ (সি ++ 11, সি ++ 14, এবং সি ++ 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 - সরাসরি নয়, তবে স্থানীয় ক্লাসের অভ্যন্তরে স্থির ফাংশন রয়েছে

সি ++ সরাসরি এটি সমর্থন করে না।

এটি বলেছিল, আপনার স্থানীয় ক্লাস থাকতে পারে এবং তাদের ফাংশন থাকতে পারে (অ- staticবা static), তাই আপনি এটি কিছুটা বর্ধিত করতে পারেন, যদিও এটি কিছুটা ক্লডজের কিছুটা হলেও:

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

  X::a();

  return 0;
}

যাইহোক, আমি প্রক্সীদের প্রশ্ন করব। প্রত্যেকেই জানেন (ভাল, এখন আপনি যেভাবেই করেন :)) সি ++ স্থানীয় ফাংশনগুলি সমর্থন করে না, তাই তারা সেগুলি না রাখার জন্য অভ্যস্ত। সেগুলি অবশ্য সেই কাদলে ব্যবহৃত হয় না। স্থানীয় কোডগুলি ব্যবহারের অনুমতি দেওয়ার জন্য এটি কেবল সেখানে রয়েছে তা নিশ্চিত করার জন্য আমি এই কোডটিতে বেশ কিছুটা সময় ব্যয় করব। ভাল না.


3
আপনি যদি রিটার্নের ধরণ সম্পর্কে প্যাডেন্টিক হন তবে মেইন দুটি টি আর্গও নেয়। :) (নাকি
লিও ডেভিডসন

3
এটি কেবল খারাপ - এটি ভাল, পরিষ্কার কোডের প্রতিটি সম্মেলন ভেঙে দেয়। আমি একটি একক উদাহরণের কথা ভাবতে পারি না যেখানে এটি একটি ভাল ধারণা।
টমাস 13

19
@ থমাস ওয়ানস: আপনার যদি কলব্যাক ফাংশন প্রয়োজন হয় এবং এটির সাথে অন্য কোনও নেমস্পেস দূষিত করতে না চান তবে এটি ভাল।
লিও ডেভিডসন 13

9
@ লিও: স্ট্যান্ডার্ডটি বলেছে যে মূলগুলির জন্য দুটি অনুমোদিত ফর্ম রয়েছে: int main()এবংint main(int argc, char* argv[])
জন ডিবলিং

8
স্ট্যান্ডার্ডটি বলেছে int main()এবং int main(int argc, char* argv[])অবশ্যই সমর্থিত হবে এবং অন্যদের সমর্থন করা যেতে পারে তবে সেগুলি সবগুলিই ফিরে এসেছে।
জোগ

260

সমস্ত উদ্দেশ্য এবং উদ্দেশ্যে, সি ++ ল্যাম্বডাসের মাধ্যমে এটি সমর্থন করে : 1

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

এখানে, fএকটি ল্যাম্বডা অবজেক্ট যা স্থানীয় ফাংশন হিসাবে কাজ করে main। স্থানীয় জিনিসগুলিতে অ্যাক্সেস করার জন্য ক্যাপচারগুলি নির্দিষ্ট করা যেতে পারে।

পর্দার আড়ালে, fএকটি ফাংশন অবজেক্ট (যেমন একটি প্রকারের একটি বস্তু যা সরবরাহ করে operator())। ল্যাম্বদার উপর ভিত্তি করে ফাংশন অবজেক্টের ধরণটি সংকলক দ্বারা তৈরি করা হয়েছে।


সি ++ 11 সাল থেকে 1


5
আহ, এ তো ঝরঝরে! আমি এটা ভাবিনি। এটি আমার ধারণা +1থেকে আমার থেকে অনেক ভাল better
sbi

1
@ এসবিআই: আমি অতীতে এটির অনুকরণের জন্য স্থানীয় স্থানীয় স্ট্রাক্টগুলি ব্যবহার করেছি (হ্যাঁ, আমি নিজের পক্ষে যথেষ্ট লজ্জিত)। তবে দরকারীতা এই কারণে সীমাবদ্ধ যে স্থানীয় স্ট্রাইকগুলি কোনও বন্ধকরণ তৈরি করে না, অর্থাৎ আপনি তাদের মধ্যে স্থানীয় ভেরিয়েবল অ্যাক্সেস করতে পারবেন না। আপনাকে এগুলি একটি নির্মাতার মাধ্যমে স্পষ্টভাবে পাস এবং স্টোর করতে হবে।
কনরাড রুডল্ফ

1
@ কনরাড: তাদের সাথে আরেকটি সমস্যা হ'ল সি ++ 98 এ আপনাকে স্থানীয় ধরণের টেমপ্লেট প্যারামিটার হিসাবে ব্যবহার করা উচিত নয়। যদিও আমি মনে করি সি ++ 1x যদিও এই সীমাবদ্ধতা সরিয়ে নিয়েছে। (বা সে সি ++ 03 ছিল?)
এসবিআই

3
@ লুইস: ফ্রেডের সাথে অবশ্যই আমাকে একমত হতে হবে। আপনি ল্যাম্বডাসের সাথে একটি অর্থ সংযুক্ত করছেন যা তাদের সহজভাবে নেই (সি ++ বা আমি যে ভাষা নিয়ে কাজ করেছি সেগুলিও নয় - যা রেকর্ডের জন্য পাইথন এবং অ্যাডাকে অন্তর্ভুক্ত করে না )। তদ্ব্যতীত, এই পার্থক্যটি তৈরি করা কেবল সি ++ এ অর্থবহ নয় কারণ সি ++ এর স্থানীয় কার্যাদি, সময়কাল নেই। এটিতে কেবল ল্যাম্বডাস রয়েছে। আপনি যদি কোনও ফাংশনের মতো কোনও ফাংশন-জাতীয় জিনিসের সুযোগ সীমাবদ্ধ করতে চান তবে আপনার কেবলমাত্র পছন্দগুলি ল্যাম্বডাস বা অন্যান্য উত্তরে উল্লিখিত স্থানীয় কাঠামো। আমি বলতে পারি যে কোনও বাস্তব আগ্রহী হওয়ার জন্য আধুনিকটি বরং খুব বেশি সংশ্লেষিত।
কনরাড রুডল্ফ

2
অস্টিন ডাব্লু ব্রায়ান নং, সি ++ এ ল্যাম্বডাস কেবল মজাদারদের জন্য সিনট্যাকটিক চিনি এবং শূন্য ওভারহেড রয়েছে। এই ওয়েবসাইটে কোথাও আরও বিশদ সহ একটি প্রশ্ন রয়েছে।
কনরাড রুডল্ফ

42

স্থানীয় ক্লাসগুলি ইতিমধ্যে উল্লেখ করা হয়েছে, তবে এখানে অপারেটর () ওভারলোড এবং একটি বেনামী ক্লাস ব্যবহার করে স্থানীয় ফাংশন হিসাবে তাদের আরও বেশি প্রদর্শিত হওয়ার উপায় এখানে:

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

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

আমি এটি ব্যবহার করার পরামর্শ দিচ্ছি না, এটি কেবল একটি মজার কৌশল (করতে পারে, তবে imho উচিত নয়)।


2014 আপডেট:

কিছুক্ষণ আগে সি ++ 11 এর উত্থানের সাথে আপনার এখন স্থানীয় ফাংশন থাকতে পারে যার বাক্য গঠনটি জাভাস্ক্রিপ্টের সাথে একটু স্মরণীয়:

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

1
হওয়া উচিত operator () (unsigned int val), আপনার বন্ধনীর একটি সেট মিস করা।
জো ডি

1
প্রকৃতপক্ষে, এটি করার একটি নিখুঁত যুক্তিযুক্ত জিনিস আপনার যদি প্রয়োজন হয় এই ফান্ট্যাক্টটিকে কোনও স্টাইল ফাংশন বা অ্যালগরিদম, যেমন std::sort(), বাতে যেতে std::for_each()
ডিমা

1
@ ডিমা: দুর্ভাগ্যক্রমে, C ++ 03 এ, স্থানীয়ভাবে সংজ্ঞায়িত প্রকারগুলি টেমপ্লেট আর্গুমেন্ট হিসাবে ব্যবহার করা যায় না। সি ++ 0 এক্স এটিকে ঠিক করে, তবে ল্যাম্বডাসের আরও ভাল সমাধান সরবরাহ করে, তাই আপনি এখনও এটি করেন না।
বেন ভয়েগট

উফ, আপনি ঠিক বলেছেন। আমার খারাপ। তবে এখনও, এটি কেবল একটি মজার কৌশল নয়। এটি অনুমোদিত হলে এটি একটি দরকারী জিনিস হত। :)
ডিমা

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

সি ++ 11 দিয়ে শুরু করে আপনি সঠিক ল্যাম্বডাস ব্যবহার করতে পারেন । আরও তথ্যের জন্য অন্যান্য উত্তর দেখুন।


পুরানো উত্তর: আপনি বাছাই করতে পারেন, তবে আপনাকে ঠকানো এবং একটি ডামি ক্লাস ব্যবহার করতে হবে:

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

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

পরিবর্তে কোনও অবজেক্ট তৈরি করে আপনি যা করতে পারবেন তা নিশ্চিত নন (এটি কেবলমাত্র গোলমাল, আইএমও যোগ করে)। নেমস্পেসগুলির সাথে আপনি করতে পারেন এমন কিছু চতুর জিনিস না থাকলে তবে আমি এটি সম্পর্কে ভাবতে পারি না এবং আমরা ইতিমধ্যে যা করছি তার চেয়ে বেশি ভাষায় অপব্যবহার করা ভাল ধারণা নয়। :)
লিও ডেভিডসন

ডামি পেয়ে যাওয়া: অন্যান্য উত্তরগুলির মধ্যে একটিতে।
সেবাস্তিয়ান মাচ

8

অন্যরা যেমন উল্লেখ করেছে, আপনি gcc এ gnu ভাষার এক্সটেনশনগুলি ব্যবহার করে নেস্টেড ফাংশনগুলি ব্যবহার করতে পারেন। যদি আপনি (বা আপনার প্রকল্প) জিসিসি টুলচেইনে আটকে থাকেন তবে আপনার কোডটি বেশিরভাগ ক্ষেত্রে জিসিসি সংকলক দ্বারা লক্ষ্যযুক্ত বিভিন্ন আর্কিটেকচার জুড়ে বহনযোগ্য।

তবে, যদি আপনার কোনও অন্য প্রয়োজনীয় সরঞ্জামের প্রয়োজন হয় যে কোনও আলাদা সরঞ্জামচইনের সাহায্যে কোডটি সংকলন করা প্রয়োজন, তবে আমি এই জাতীয় এক্সটেনশনগুলি থেকে দূরে থাকব।


নেস্টেড ফাংশনগুলি ব্যবহার করার সময় আমি যত্ন সহকারে পদক্ষেপও করতাম। জটিল, তবুও কোডের সমন্বয়মূলক ব্লকগুলির কাঠামো পরিচালনার জন্য এগুলি একটি সুন্দর সমাধান (এর টুকরোগুলি বাহ্যিক / সাধারণ ব্যবহারের জন্য নয়) এটি নেমস্পেস দূষণ নিয়ন্ত্রণেও খুব সহায়ক (প্রাকৃতিক জটিল / একটি অত্যন্ত বাস্তব উদ্বেগ) ভার্বোজ ভাষায় দীর্ঘ ক্লাস।)

তবে যে কোনও কিছুর মতো এগুলি আপত্তিজনকভাবে উন্মুক্ত থাকতে পারে।

এটি দুঃখজনক যে সি / সি ++ স্ট্যান্ডার্ড হিসাবে এই জাতীয় বৈশিষ্ট্যগুলি সমর্থন করে না। বেশিরভাগ প্যাস্কাল ভেরিয়েন্ট এবং অ্যাডা ডো (প্রায় সমস্ত আলগোল ভিত্তিক ভাষাগুলিই করে)। জাভাস্ক্রিপ্ট একই। স্কালার মতো আধুনিক ভাষার সাথেও। এর্লং, লিস্প বা পাইথনের মতো শ্রদ্ধেয় ভাষার সাথে একই।

এবং ঠিক যেমন সি / সি ++ এর সাথে, দুর্ভাগ্যক্রমে, জাভা (যা দিয়ে আমি আমার বেশিরভাগ জীবন উপার্জন করি) তা করে না।

আমি এখানে জাভা উল্লেখ করেছি কারণ আমি বেশ কয়েকটি পোস্টার দেখতে পেয়েছি যাতে নেস্টেড ফাংশনগুলির বিকল্প হিসাবে ক্লাস এবং ক্লাসের পদ্ধতি ব্যবহারের পরামর্শ দেওয়া হচ্ছে। এবং এটি জাভাতে সাধারণ কাজও নয়।

সংক্ষিপ্ত উত্তর: না

এটি করার ফলে শ্রেণিবদ্ধ শ্রেণিতে কৃত্রিম, অযথা জটিলতার পরিচয় দেওয়া হয়। সমস্ত জিনিস সমান হওয়ার সাথে সাথে আদর্শটি হ'ল একটি শ্রেণিবদ্ধ স্তর (এবং এর অন্তর্ভুক্ত নেমস্পেস এবং স্কোপস) যথাসম্ভব সহজ একটি বাস্তব ডোমেনকে উপস্থাপন করা।

নেস্টেড ফাংশনগুলি "ব্যক্তিগত", কার্যকারিতা জটিলতার সাথে ডিল করতে সহায়তা করে। এই সুবিধার অভাবের কারণে, সেই "ব্যক্তিগত" জটিলতার প্রচার এবং নিজের শ্রেণির মডেলটিকে প্রচার করা এড়ানো উচিত।

সফ্টওয়্যার (এবং যে কোনও ইঞ্জিনিয়ারিং বিভাগে), মডেলিং ট্রেড অফের বিষয়। সুতরাং, বাস্তব জীবনে, এই নিয়মগুলির (বা বরং নির্দেশিকা) যথাযথ ব্যতিক্রম হবে। যত্ন সহকারে এগিয়ে যান, যদিও।


8

সি ++ এ আপনার স্থানীয় ফাংশন থাকতে পারে না। তবে সি ++ 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

না, এটি অনুমোদিত নয়। সি বা সি ++ উভয়ই ডিফল্টরূপে এই বৈশিষ্ট্যটিকে সমর্থন করে না, তবে টনিক (মন্তব্যগুলিতে) উল্লেখ করেছেন যে জিএনইউ সি সংকলকটির এক্সটেনশন রয়েছে যা সিতে এই আচরণকে সক্ষম করে enable


2
এটি একটি বিশেষ এক্সটেনশন হিসাবে GNU সি সংকলক দ্বারা সমর্থিত। তবে কেবল সি এর জন্য, সি ++ নয়।
টনিক

আহ। আমার সি কম্পাইলারে আমার কোনও বিশেষ এক্সটেনশন নেই। যদিও এটি জেনে রাখা ভাল। আমি আমার উত্তরে সেই শিরোনামটি যুক্ত করব।
থমাস

নেস্টেড ফাংশনগুলির সমর্থনের জন্য আমি সিসি এক্সটেনশন ব্যবহার করেছি (সি তে, যদিও সি ++ নয়)। নেস্টেড ফাংশনগুলি জটিল, তবে একত্রী কাঠামোগুলি পরিচালনা করার জন্য একটি নিফটি জিনিস (সাধারণভাবে ব্যবহারের জন্য বোঝানো হয় না) co যতক্ষণ না কেউ জিসিসি সরঞ্জামচেন ব্যবহার করে, ততক্ষণ এটি লক্ষ্যযুক্ত আর্কিটেকচারের বেশিরভাগ ক্ষেত্রে পোর্টেবল হওয়ার আশ্বাস দেওয়া হয় । তবে যদি কোনও নন-জিসিসি সংকলক সহ ফলাফল কোডটি সংকলন করার কোনও পরিবর্তন ঘটে থাকে, তবে, এই জাতীয় এক্সটেনশনগুলি এড়ানো এবং যতটা সম্ভব অ্যানসি / পোস্টিক্স মন্ত্রের সাথে সংযুক্ত থাকা ভাল।
luis.espinal

7

এই সমস্ত কৌশলগুলি কেবল স্থানীয় ফাংশন হিসাবে দেখায় (কম বা কম) তবে তারা সেভাবে কাজ করে না। স্থানীয় ফাংশনে আপনি এর সুপার ফাংশনগুলির স্থানীয় ভেরিয়েবলগুলি ব্যবহার করতে পারেন। এটি একধরনের সেমি-গ্লোবাল। এই কৌশলগুলি না করে এটি করতে পারে। নিকটতমটি সি ++ 0 এক্স থেকে ল্যাম্বডা ট্রিক, তবে এটি বন্ধ হওয়ার সময় সংজ্ঞায়নের সময় আবদ্ধ, ব্যবহারের সময় নয়।


এখন আমি মনে করি এটিই সেরা উত্তর। যদিও কোনও ফাংশনটির মধ্যে কোনও ফাংশন ঘোষণা করা সম্ভব (যা আমি সর্বদা ব্যবহার করি) এটি অন্য কোনও ভাষায় সংজ্ঞায়িত স্থানীয় ফাংশন নয়। সম্ভাবনাটি জানা এখনও ভাল।
অ্যালেক্সিস উইল্ক

6

আপনি অন্য + এর ভিতরে ফ্রি ফাংশনটি সি ++ এ সংজ্ঞায়িত করতে পারবেন না।


1
আনসী / পিক্সিসহ নয়, আপনি gnu এক্সটেনশানগুলি সহ করতে পারেন।
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;
}

(*) সি ++ বিশ্বে ম্যাক্রো ব্যবহার করে কখনই পরিষ্কার বলে বিবেচিত হয় না।


অ্যালেক্সিস, আপনি ঠিকই বলেছেন যে এটি পুরোপুরি পরিষ্কার নয়। এটি এখনও পরিষ্কার হওয়ার কাছাকাছি রয়েছে কারণ এটি পার্শ্ব-প্রতিক্রিয়া ছাড়াই প্রোগ্রামারটি কী বোঝাতে চেয়েছিল তা ভালভাবে প্রকাশ করে। আমি বিবেচনা করি প্রোগ্রামিংয়ের শিল্পটি মানব-পঠনযোগ্য ভাববাদী লিখছে যা একটি উপন্যাসের মতো পড়ে।
বার্নি

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());
}

=> কোনও প্রোগ্রাম আউটপুট নেই।

(সংকলনের পরে কেবল কলঙ্কের সতর্কতা)।

সি ++ এর সর্বাধিক ভেক্সিং পার্স আবার ars

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.