লাম্বদা এক্সপ্রেশন ফিরিয়ে ফাংশন


89

আমি অবাক হয়েছি যদি এমন একটি ফাংশন লেখা সম্ভব হয় যা C ++ 11 এ ল্যাম্বডা ফাংশনটি ফেরত দেয়। অবশ্যই একটি সমস্যা হ'ল এই জাতীয় ফাংশন কীভাবে ঘোষণা করা যায়। প্রতিটি ল্যাম্বডায় একটি প্রকার থাকে তবে সেই ধরণটি সি ++ তে প্রকাশযোগ্য নয়। আমি মনে করি না এটি কাজ করবে:

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

না এটি:

int(int) retFun();

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


4
ইতিমধ্যে যা বলা হয়েছে তা যুক্ত করতে স্টেটলেস ল্যাম্বডা ফাংশনগুলি ফাংশন পয়েন্টারে রূপান্তরিত হয়।
snk_kid

4
আইএমও আপনার প্রথম বিকল্পটি কাজ করবে না যেহেতু ল্যাম্বদা decltypeফাংশন বডিটির মতো নয় এবং তাই আলাদা ধরণের রয়েছে (আপনি রিটার্নের বিবৃতি অন্তর্ভুক্ত করলেও)
মোটি

4
যাইহোক, যদি কোনও ল্যাম্বডায় একটি খালি ক্যাপচারের ধারা থাকে তবে এটি কার্যকরীভাবে পয়েন্টারের কাছে স্পষ্টত রূপান্তরিত হতে পারে।
GManNickG

@ জিএমান: আপনি ভিজ্যুয়াল সি ++ 2010 ব্যবহার না করে বা জি ++ এর একটি সংস্করণ প্রায় এক বছর আগে (বা তার আশেপাশে) ছাড়িয়ে বেশি প্রকাশ করেছেন। ফাংশন পয়েন্টারে ক্যাপচারলেস-ল্যাম্বদা অন্তর্ভুক্ত রূপান্তরটি N3092 এ মার্চ ২০১০ পর্যন্ত যুক্ত করা হয়নি।
জেমস ম্যাকনেলিস

4
ল্যাম্বডা এক্সপ্রেশনটি সাধারণভাবে অমূল্য সংযোজনগুলিতে উপস্থিত হতে পারে। আপনি যেখানেই লিখুন না কেন decltype([](){})বা sizeof([]() {})অ-গঠিত
জোহানেস স্কাউব - লিটব

উত্তর:


99

আপনার কোনও হস্তশিল্পের ফাংশন অবজেক্টের প্রয়োজন নেই, কেবল ব্যবহার করুন std::function, যা ল্যাম্বডা ফাংশনগুলি রূপান্তরযোগ্য:

এই উদাহরণটি পূর্ণসংখ্যার পরিচয় ফাংশন প্রদান করে:

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

6
দুহ! আমি স্ট্যাকওভারফ্লো পছন্দ করি। বিষয়টি গবেষণা করতে স্ট্যাকওভারফ্লোতে উত্তর পেতে আমার আরও বেশি সময় লাগত। থ্যাঙ্কস শান!
বার্টোসজ মাইলিউস্কি

6
এটি নির্মাণকারী যদিও মেমরি বরাদ্দ হতে চলেছে std::function
ম্যাক্সিম এগারুশকিন

4
@ ম্যাক্সিম ইয়েগুরুশকিন স্টডি :: ফাংশনটিতে শব্দার্থক পদক্ষেপ রয়েছে এবং এটি কাস্টম বরাদ্দকারীদের ব্যবহার করতে পারে এবং সি ++ 0 এক্স ওয়ার্কিং ড্রাফ্টে এই নোটগুলি রয়েছে: "[দ্রষ্টব্য: ছোট কলযোগ্য বস্তুর জন্য গতিময় বরাদ্দ মেমরির ব্যবহার এড়াতে বাস্তবায়নকে উত্সাহ দেওয়া হয়, উদাহরণস্বরূপ , যেখানে f এর লক্ষ্যমাত্রা এমন একটি অবজেক্ট যা কেবলমাত্র একটি পয়েন্টার বা কোনও অবজেক্টের সাথে রেফারেন্স এবং সদস্য ফাংশন পয়েন্টার ধারণ করে — অন্তর্ভুক্ত নোট] "সুতরাং মূলত আপনি কোন নির্দিষ্ট বরাদ্দ কৌশলটি ব্যবহার করছেন তা সম্পর্কে অনেক অনুমান করা যায় না তবে আপনি সক্ষম হবেন যাইহোক আপনার নিজের (পোল্ড) বরাদ্দকারী ব্যবহার করতে।
snk_kid

4
@ ম্যাক্সিম: আমার প্রশ্নের উত্তর ছিল "" একমাত্র সমাধানটি কোনও ফাংশনটির জন্য হস্তশিল্প তৈরি করে তা ফিরিয়ে দেওয়া কি? "
শান

4
কেবল মনে রাখবেন যে 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; };
}

এটাই আমার বোঝাপড়া, আমি ভুল হলে আমাকে সংশোধন করুন।


4
এটা ঠিক শোনাচ্ছে। দুর্ভাগ্যক্রমে, এটি যে বর্তমান সংকলকটি আমি ব্যবহার করছি তার সাথে এটি কাজ করে না: ভিএস 2010. স্টাড :: ফাংশন রূপান্তরটি কাজ করে।
বার্তোসলে মাইলিউস্কি

4
হ্যাঁ, এই নিয়মের চূড়ান্ত শব্দটি VC2010 এর জন্য খুব দেরিতে এসেছিল।
বেন ভয়েগট

আমি কোড উদাহরণ যুক্ত করেছি। এখানে একটি সম্পূর্ণ প্রোগ্রাম
jfs

@ জেএফএসবেস্তিয়ান - এই উদাহরণে ল্যাম্বডের জীবনকাল কী? ফাংশন পয়েন্টারে রূপান্তরিত হওয়ার ফলাফলটি কি বহুকাল বহন করতে যথেষ্ট?
ফ্লেক্সো

4
: - @JFSebastian আমি তাই আমি তার নিজের অধিকার একটি প্রশ্ন যেমন জিজ্ঞাসা করেছি যে উত্তর খুঁজে মনে করতে পারে না stackoverflow.com/questions/8026170/...
Flexo

22

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

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

4
এটি কেবল সত্য যখন বাইরের ল্যাম্বদাটি কেবল রিটার্নের বিবৃতি নিয়ে গঠিত। অন্যথায় আপনাকে রিটার্নের ধরণ নির্দিষ্ট করতে হবে।
বার্তোস মাইলিউস্কি

4
এই সর্বোত্তম উত্তর যেমন এসটিডি :: ফাংশনের রানটাইম পলিমরফিজম প্রয়োজন হয় না এবং একটি খালি ক্যাপচার তালিকা আছে ল্যামডা জন্য করতে পারবেন, তবে আমি ব্যবহার করেন const স্বয়ংক্রিয় মজা = ...
robson3.14

4
@ বার্তোসমেলেউস্কি সি ++ ১৪-এর পর থেকে সত্য নয়।
dzhioev

20

যদিও প্রশ্নটি বিশেষত সি ++ 11 সম্পর্কে জিজ্ঞাসা করে, অন্যদের জন্য যারা এই বিষয়ে হোঁচট খায় এবং সি ++ 14 সংকলকটিতে অ্যাক্সেস পেয়েছে, সি ++ 14 এখন সাধারণ ফাংশনগুলির জন্য কাটা ফিরতি প্রকারের অনুমতি দেয়। সুতরাং প্রশ্নের উদাহরণটি -> decltypeফাংশন প্যারামিটার তালিকার পরে ... ধারাটি বাদ দিয়ে কেবল কাঙ্ক্ষিত হিসাবে কাজ করতে সামঞ্জস্য করা যেতে পারে :

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

তবে দ্রষ্টব্য, return <lambda>;ফাংশনে একাধিক উপস্থিত থাকলে এটি কাজ করবে না । এটি কারণ রিটার্ন টাইপ ছাড়ের উপর একটি বিধিনিষেধটি হ'ল সমস্ত রিটার্ন স্টেটমেন্টগুলি অবশ্যই একই ধরণের এক্সপ্রেশনগুলি ফেরত পাঠায় তবে প্রতিটি ল্যাম্বডা অবজেক্টটি সংকলক দ্বারা নিজস্ব স্বতন্ত্র প্রকারের দেওয়া হয়, সুতরাং return <lambda>;প্রতিটিটিরই বর্ণ আলাদা আলাদা রকমের হবে।


4
কেন সি ++ 14 এর কাটা ধরণের প্রকারগুলি উল্লেখ করুন তবে বহুকর্মী ল্যাম্বডাস বাদ দেন? auto retFun() { return [](auto const& x) { return x; }; }
sehe

1

আপনার এইরকম লেখা উচিত:

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

একটি ফাংশন হিসাবে আপনার রিটার্ন পেতে, এবং এটি ব্যবহার করুন:

int val = returnFunction(someNumber);

0

আপনার যদি সি ++ 11 না থাকে এবং উদাহরণস্বরূপ মাইক্রো কন্ট্রোলারে আপনার সি ++ কোড চালাচ্ছেন। আপনি একটি অকার্যকর পয়েন্টারটি ফিরিয়ে দিতে পারেন এবং তারপরে একটি কাস্ট সম্পাদন করতে পারেন।

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();
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.