সি ++ 11 এ ল্যাম্বডা এক্সপ্রেশনটি কী? আমি কখন এটি ব্যবহার করব? তারা কোন শ্রেণীর সমস্যার সমাধান করেন যা তাদের পরিচয়ের আগে সম্ভব হয়নি?
কয়েকটি উদাহরণ এবং ব্যবহারের ক্ষেত্রে দরকারী হবে।
সি ++ 11 এ ল্যাম্বডা এক্সপ্রেশনটি কী? আমি কখন এটি ব্যবহার করব? তারা কোন শ্রেণীর সমস্যার সমাধান করেন যা তাদের পরিচয়ের আগে সম্ভব হয়নি?
কয়েকটি উদাহরণ এবং ব্যবহারের ক্ষেত্রে দরকারী হবে।
উত্তর:
সি ++ এর মতো দরকারী জেনেরিক ফাংশন রয়েছে std::for_each
এবং std::transform
যা খুব সহজেই কার্যকর হতে পারে। দুর্ভাগ্যক্রমে তারা ব্যবহারের জন্যও বেশ জটিল হয়ে উঠতে পারে, বিশেষত যদি আপনি যে ফান্টার প্রয়োগ করতে চান এটি নির্দিষ্ট ফাংশনের জন্য অনন্য।
#include <algorithm>
#include <vector>
namespace {
struct f {
void operator()(int) {
// do something
}
};
}
void func(std::vector<int>& v) {
f f;
std::for_each(v.begin(), v.end(), f);
}
আপনি যদি কেবল f
একবার এবং সেই নির্দিষ্ট জায়গায় ব্যবহার করেন তবে মনে হয় অতিমাত্রায় কিছু তুচ্ছ এবং কিছু বন্ধ করার জন্য একটি সম্পূর্ণ শ্রেণি লিখছেন।
সি ++ তে আপনাকে ফান্টারকে স্থানীয় রাখার জন্য নীচের মতো কিছু লিখতে প্ররোচিত হতে পারে:
void func2(std::vector<int>& v) {
struct {
void operator()(int) {
// do something
}
} f;
std::for_each(v.begin(), v.end(), f);
}
তবে এটি অনুমোদিত নয়, সি ++ 03 f
তে কোনও টেম্পলেট ফাংশনে পাঠানো যাবে না ।
সি ++ 11 ল্যাম্বডাসের সাথে পরিচয় করিয়ে দিচ্ছে আপনাকে একটি প্রতিস্থাপনের জন্য একটি ইনলাইন, বেনামি ফান্টেক্টর লেখার অনুমতি দেয় struct f
। ছোট ছোট উদাহরণগুলির জন্য এটি পড়ার জন্য পরিষ্কার হতে পারে (এটি সবকিছুকে এক জায়গায় রাখে) এবং বজায় রাখা সম্ভাব্যতর সহজ, উদাহরণস্বরূপ সহজতম আকারে:
void func3(std::vector<int>& v) {
std::for_each(v.begin(), v.end(), [](int) { /* do something here*/ });
}
লাম্বদা ফাংশনগুলি বেনামি ফান্টেক্টরগুলির জন্য কেবল সিনট্যাকটিক চিনি।
সাধারণ ক্ষেত্রে ল্যাম্বদার রিটার্নের ধরণটি আপনার জন্য কেটে নেওয়া হয়, যেমন:
void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) { return d < 0.00001 ? 0 : d; }
);
}
তবে আপনি যখন আরও জটিল ল্যাম্বডাস লিখতে শুরু করেন তখন আপনি দ্রুত এমন কেসগুলির মুখোমুখি হবেন যেখানে সংকলক দ্বারা রিটার্নের ধরণটি কেটে নেওয়া যায় না, যেমন:
void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) {
if (d < 0.0001) {
return 0;
} else {
return d;
}
});
}
এটি সমাধানের জন্য আপনাকে ল্যাম্বডা ফাংশনের জন্য স্পষ্ট করে একটি রিটার্ন টাইপ নির্দিষ্ট করার অনুমতি দেওয়া হয়েছে -> T
:
void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) -> double {
if (d < 0.0001) {
return 0;
} else {
return d;
}
});
}
এখনও অবধি আমরা এর মধ্যে ল্যাম্বডায় যা যা হয়েছে তা ব্যতীত অন্য কিছু ব্যবহার করি নি, তবে আমরা ল্যাম্বদার মধ্যে অন্যান্য ভেরিয়েবলগুলিও ব্যবহার করতে পারি। আপনি যদি অন্যান্য ভেরিয়েবল অ্যাক্সেস করতে চান তবে আপনি ক্যাপচার ক্লজটি ( []
এক্সপ্রেশনটির) ব্যবহার করতে পারেন , যা এখনও পর্যন্ত এই উদাহরণগুলিতে অব্যবহৃত হয়েছে, যেমন:
void func5(std::vector<double>& v, const double& epsilon) {
std::transform(v.begin(), v.end(), v.begin(),
[epsilon](double d) -> double {
if (d < epsilon) {
return 0;
} else {
return d;
}
});
}
আপনি উভয় রেফারেন্স এবং মান, যা আপনি ব্যবহার নির্দিষ্ট করতে পারেন দ্বারা ক্যাপচার করতে পারেন &
এবং =
যথাক্রমে:
[&epsilon]
রেফারেন্স দ্বারা ক্যাপচার[&]
রেফারেন্স দ্বারা ল্যাম্বডায় ব্যবহৃত সমস্ত ভেরিয়েবল ক্যাপচার করে[=]
মান অনুসারে ল্যাম্বডায় ব্যবহৃত সমস্ত ভেরিয়েবল ক্যাপচার করে[&, epsilon]
[&] এর মতো চলকগুলি ক্যাপচার করে তবে মান অনুসারে এপসিলন[=, &epsilon]
[=] এর মতো চলকগুলি ক্যাপচার করে তবে রেফারেন্স অনুসারে এপসিলনউত্পন্ন operator()
হ'ল const
ডিফল্টরূপে, জড়িত ইমপ্লিকেশন সহ const
যখন আপনি ডিফল্টরূপে সেগুলি অ্যাক্সেস করেন তখন ক্যাপচারগুলি ঘটে। এটির প্রভাব রয়েছে যে একই ইনপুট সহ প্রতিটি কল একই ফলাফল আনতে পারে তবে আপনি ল্যাম্বডাকে চিহ্নিতmutable
করতে পারেন operator()
যে উত্পন্ন হয় না তা অনুরোধ করতে const
।
const
সর্বদা ...
()
- এটি শূন্য-যুক্তিযুক্ত ল্যাম্বডা হিসাবে পাস করা হয়েছে, তবে ল্যাম্বদার সাথে এটি () const
মেলে না, এটি এমন ধরণের রূপান্তরকে সন্ধান করে যা এটির অনুমতি দেয়, যার মধ্যে অন্তর্ভুক্ত-কাস্ট থাকে -তে-ফাংশন-পয়েন্টার, এবং তারপরে কল করে! নিনজা!
std::function<double(int, bool)> f = [](int a, bool b) -> double { ... };
তবে সাধারণত, আমরা সংকলকটি টাইপটি auto f = [](int a, bool b) -> double { ... };
#include <functional>
return d < 0.00001 ? 0 : d;
ডাবল ফেরতের গ্যারান্টি দেওয়া হয়, যখন কোনও অপারেটর একটি পূর্ণসংখ্যার ধ্রুবক হয় (এটি কারণটির কোনও অন্তর্নিহিত প্রচারের নিয়মের কারণে?: অপারেটর যেখানে 2 য় এবং 3 য় অপারেন্ড স্বাভাবিক গাণিতিকের মাধ্যমে একে অপরের বিরুদ্ধে ভারসাম্যপূর্ণ হয়) রূপান্তরগুলি কোনওটিই বাছাই করে নিন)। পরিবর্তন করা 0.0 : d
সম্ভবত উদাহরণটি বুঝতে সহজতর হবে।
ল্যাম্বডা ফাংশনের সি ++ ধারণাটি ল্যাম্বডা ক্যালকুলাস এবং ফাংশনাল প্রোগ্রামিংয়ে উত্পন্ন হয়। একটি ল্যাম্বডা একটি নামহীন ফাংশন যা কোডের সংক্ষিপ্ত স্নিপেটগুলির জন্য দরকারী (প্রকৃত প্রোগ্রামিংয়ে, তত্ত্ব নয়) যা নাম ব্যবহার করার পক্ষে অসম্ভব এবং নামকরণের জন্য উপযুক্ত নয়।
সি ++ এ একটি ল্যাম্বডা ফাংশনটি এভাবে সংজ্ঞায়িত করা হয়
[]() { } // barebone lambda
বা সমস্ত গৌরব
[]() mutable -> T { } // T is the return type, still lacking throw()
[]
ক্যাপচার তালিকা, ()
আর্গুমেন্ট তালিকা এবং {}
ফাংশন বডি।
ক্যাপচার তালিকায় লাম্বদার বাইরে থেকে কী ফাংশন বডির ভিতরে পাওয়া উচিত এবং কীভাবে তা নির্ধারণ করে। এটি হয় হতে পারে:
আপনি উপরোক্ত যে কোনও একটি কমা দ্বারা পৃথক করা তালিকায় মিশ্রিত করতে পারেন [x, &y]
।
আর্গুমেন্টের তালিকা অন্য যে কোনও সি ++ ফাংশনের মতো।
ল্যাম্বডা আসলে কল করার সময় কোডটি কার্যকর করা হবে।
যদি কোনও ল্যাম্বডায় কেবল একটি রিটার্নের বিবৃতি থাকে তবে রিটার্নের ধরণটি বাদ দেওয়া যেতে পারে এবং এতে অন্তর্নিহিত ধরণের থাকে decltype(return_statement)
।
যদি কোনও ল্যাম্বডা পরিবর্তনীয় (উদাহরণস্বরূপ []() mutable { }
) চিহ্নিত হয় তবে এটি মান দ্বারা ক্যাপচার করা মানগুলিকে রূপান্তর করতে অনুমতি দেয়।
আইএসও স্ট্যান্ডার্ড দ্বারা সংজ্ঞায়িত গ্রন্থাগারটি ল্যাম্বডাস থেকে প্রচুর উপকার লাভ করে এবং ব্যবহারযোগ্যতা বেশ কয়েকটি বার উত্থাপন করে কারণ এখন ব্যবহারকারীদের কিছু অ্যাক্সেসযোগ্য সুযোগে ছোট ফান্টারের সাথে তাদের কোডটি বিশৃঙ্খলা করতে হবে না।
সি ++ এ 14 টি ল্যাম্বডাস বিভিন্ন প্রস্তাব দ্বারা বাড়ানো হয়েছে।
ক্যাপচার তালিকার একটি উপাদান দিয়ে এখন আরম্ভ করা যেতে পারে =
। এটি ভেরিয়েবলের নাম পরিবর্তন করতে এবং স্থানান্তরিত করে ক্যাপচার করতে সহায়তা করে। মান থেকে নেওয়া একটি উদাহরণ:
int x = 4;
auto y = [&r = x, x = x+1]()->int {
r += 2;
return x+2;
}(); // Updates ::x to 6, and initializes y to 7.
এবং উইকিপিডিয়া থেকে নেওয়া একজন কীভাবে কীভাবে ক্যাপচার করবেন তা দেখায় std::move
:
auto ptr = std::make_unique<int>(10); // See below for std::make_unique
auto lambda = [ptr = std::move(ptr)] {return *ptr;};
লাম্বদাস এখন জেনেরিক auto
হতে পারে ( পার্শ্ববর্তী ক্ষেত্রের কোথাও কোনও ধরণের টেম্পলেট যুক্তি T
থাকলে এখানে
সমতুল্য হবে T
):
auto lambda = [](auto x, auto y) {return x + y;};
সি ++ 14 প্রতিটি ফাংশনের জন্য হ্রাস প্রাপ্ত রিটার্নের ধরণের অনুমতি দেয় এবং এটি ফর্মের ফাংশনে সীমাবদ্ধ করে না return expression;
। এটি ল্যাম্বডাসেও প্রসারিত।
r = &x; r += 2;
তবে এটি মূল মানের সাথে ঘটে 4
লাম্বদা এক্সপ্রেশনগুলি সাধারণত অ্যালগরিদমগুলি এনপ্যাপুলেট করতে ব্যবহৃত হয় যাতে সেগুলি অন্য কোনও ফাংশনে যেতে পারে। তবে সংজ্ঞা অনুসারে একটি ল্যাম্বডা কার্যকর করা সম্ভব :
[&](){ ...your code... }(); // immediately executed lambda expression
কার্যত সমতুল্য
{ ...your code... } // simple code block
এটি ল্যাম্বদা এক্সপ্রেশনগুলি জটিল ফাংশনগুলি রিফ্যাক্টর করার জন্য একটি শক্তিশালী সরঞ্জাম করে । আপনি উপরে বর্ণিত ল্যাম্বদা ফাংশনে একটি কোড বিভাগ মোড়ানো দিয়ে শুরু করুন। সুস্পষ্ট প্যারামিটারাইজেশন প্রক্রিয়াটি প্রতিটি ধাপের পরে মধ্যবর্তী পরীক্ষার মাধ্যমে ধীরে ধীরে সম্পাদিত হতে পারে। আপনার একবার কোড-ব্লক পুরোপুরি প্যারামিটারাইজড হয়ে গেছে (যেমন মুছে ফেলার মাধ্যমে প্রদর্শিত হয়েছে &
), আপনি কোডটি একটি বাহ্যিক স্থানে নিয়ে যেতে এবং এটিকে একটি সাধারণ ফাংশন করতে পারেন।
একইভাবে, আপনি একটি অ্যালগোরিদমের ফলাফলের ভিত্তিতে ভেরিয়েবল শুরু করতে ল্যাম্বদা এক্সপ্রেশন ব্যবহার করতে পারেন ...
int a = []( int b ){ int r=1; while (b>0) r*=b--; return r; }(5); // 5!
আপনার প্রোগ্রাম লজিক বিভাজনের একটি উপায় হিসাবে , আপনি এমনকি অন্য ল্যাম্বডা এক্সপ্রেশন যুক্তি হিসাবে একটি ল্যাম্বডা এক্সপ্রেশন পাস করতে দরকারী মনে হতে পারে ...
[&]( std::function<void()> algorithm ) // wrapper section
{
...your wrapper code...
algorithm();
...your wrapper code...
}
([&]() // algorithm section
{
...your algorithm code...
});
লাম্বদা এক্সপ্রেশন আপনাকে নামযুক্ত নেটিভ ফাংশনগুলি তৈরি করতে দেয় যা সদৃশ যুক্তি এড়ানোর সুবিধাজনক উপায় হতে পারে। অন্য কোনও ফাংশনের প্যারামিটার হিসাবে একটি তুচ্ছ-তুচ্ছ ফাংশনটি পাস করার সময় নামহীন ল্যাম্বডাস ব্যবহার করাও চোখের কাছে কিছুটা সহজ হয়ে যায় (বেনামে ইনলাইন ল্যাম্বডাসের তুলনায়)। দ্রষ্টব্য: সমাপ্তি কোঁকড়া ধনুর্বন্ধনী পরে সেমিকোলন ভুলবেন না।
auto algorithm = [&]( double x, double m, double b ) -> double
{
return m*x+b;
};
int a=algorithm(1,2,3), b=algorithm(4,5,6);
যদি পরবর্তী প্রোফাইলগুলি ফাংশন অবজেক্টের জন্য উল্লেখযোগ্য আরম্ভের ওভারহেড প্রকাশ করে, আপনি এটি একটি সাধারণ ফাংশন হিসাবে পুনরায় লিখতে পছন্দ করতে পারেন।
if
বিবৃতিগুলির প্রতিপত্তি হিসাবে কাজ করে:, if ([i]{ for (char j : i) if (!isspace(j)) return false ; return true ; }()) // i is all whitespace
ধরে i
নেওয়া একটি এটিstd::string
[](){}();
।
(lambda: None)()
সিনট্যাক্সটি আরও অনেক সুস্পষ্ট।
main() {{{{((([](){{}}())));}}}}
উত্তর
প্রশ্ন: সি ++ 11 এ ল্যাম্বডা এক্সপ্রেশনটি কী?
উত্তর: ফণা অধীনে, এটি ওভারলোডিং অপারেটর () কনস্টের সাথে একটি স্বয়ংজেনারেটেড শ্রেণীর অবজেক্ট । এই জাতীয় অবজেক্টকে ক্লোজার বলা হয় এবং সংকলক তৈরি করে। এই 'ক্লোজার' ধারণাটি সি ++ 11 থেকে বাইন্ড ধারণার সাথে কাছে। তবে ল্যাম্বডাস সাধারণত আরও ভাল কোড তৈরি করে। এবং ক্লোজারগুলির মাধ্যমে কলগুলি সম্পূর্ণ ইনলাইনিংয়ের অনুমতি দেয়।
প্রশ্ন: আমি কখন এটি ব্যবহার করব?
উত্তর: "সাধারণ এবং ছোট যুক্তি" সংজ্ঞায়িত করতে এবং পূর্ববর্তী প্রশ্ন থেকে সংকলক সম্পাদন প্রজন্মকে জিজ্ঞাসা করুন। আপনি একটি সংকলককে কিছু এক্সপ্রেশন দিয়েছেন যা আপনি অপারেটর () এর ভিতরে থাকতে চান। অন্যান্য সমস্ত স্টোর সংকলক আপনার কাছে উত্পন্ন করবে।
প্রশ্ন: তারা কোন শ্রেণীর সমস্যার সমাধান করেন যা তাদের পরিচয় হওয়ার আগে সম্ভব ছিল না?
উত্তর: এটি এক ধরণের সিনট্যাক্স চিনির মতো কাস্টম অ্যাড, সাবট্যাক্ট অপারেশনগুলির পরিবর্তে অপারেটরদের ওভারলোডিং ... তবে এটি কিছু ক্লাসে বাস্তব লজিকের ১-২ লাইন মোড়ানোর জন্য অপ্রয়োজনীয় কোডের আরও লাইন সংরক্ষণ করে! কিছু প্রকৌশলী মনে করেন যে লাইনের সংখ্যা যদি কম হয় তবে এতে ত্রুটি করার কম সুযোগ থাকবে (আমিও তাই মনে করি)
ব্যবহারের উদাহরণ
auto x = [=](int arg1){printf("%i", arg1); };
void(*f)(int) = x;
f(1);
x(1);
ল্যাম্বডাস সম্পর্কে অতিরিক্ত, প্রশ্ন দ্বারা আবৃত নয়। আপনার আগ্রহ না থাকলে এই বিভাগটি উপেক্ষা করুন
1. ক্যাপচারিত মান। আপনি ক্যাপচার করতে পারেন
1.1। ল্যাম্বডাসে স্থির স্টোরেজ সময়কাল সহ আপনি একটি পরিবর্তনশীল উল্লেখ করতে পারেন। তারা সবাই বন্দী।
1.2। আপনি "মান অনুসারে" ক্যাপচারের জন্য ল্যাম্বদা ব্যবহার করতে পারেন। এই ক্ষেত্রে ক্যাপচার করা ভারগুলি ফাংশন অবজেক্টে (ক্লোজার) অনুলিপি করা হবে।
[captureVar1,captureVar2](int arg1){}
1.3। আপনি রেফারেন্স হতে পারে ক্যাপচার। & - এই প্রসঙ্গে রেফারেন্স মানে পয়েন্টার নয়।
[&captureVar1,&captureVar2](int arg1){}
1.4। মান দ্বারা বা রেফারেন্স দ্বারা সমস্ত অ স্থিতিশীল ভারগুলি ক্যাপচারের জন্য এটি স্বরলিপি উপস্থিত রয়েছে
[=](int arg1){} // capture all not-static vars by value
[&](int arg1){} // capture all not-static vars by reference
1.5। মান দ্বারা বা রেফারেন্স দ্বারা এবং এসএমএটি নির্দিষ্ট করে সমস্ত অ স্থিত ভার ক্যাপচার করার জন্য এটি চিহ্নিতকরণ বিদ্যমান ation আরও অনেক কিছু। উদাহরণস্বরূপ: মান অনুসারে সমস্ত স্থিতিশীল ভারগুলি ক্যাপচার করুন, কিন্তু রেফারেন্স ক্যাপচার দ্বারা পরম 2
[=,&Param2](int arg1){}
রেফারেন্স দ্বারা সমস্ত স্থিতিশীল ভারগুলি ক্যাপচার করুন তবে মান ক্যাপচার করুন প্যারাম 2
[&,Param2](int arg1){}
২. রিটার্ন টাইপ ছাড়
2.1। ল্যাম্বদা রিটার্ন টাইপটি বাদ দেওয়া যেতে পারে যদি ল্যাম্বদা একপ্রকাশ হয়। অথবা আপনি স্পষ্টভাবে এটি নির্দিষ্ট করতে পারেন।
[=](int arg1)->trailing_return_type{return trailing_return_type();}
ল্যাম্বদার যদি আরও একটি প্রকাশ থাকে তবে রিটার্ন টাইপটি অবশ্যই ট্রিলিং রিটার্ন টাইপের মাধ্যমে নির্দিষ্ট করতে হবে। এছাড়াও, অটো ফাংশন এবং সদস্য-ফাংশনগুলিতে অনুরূপ সিনট্যাক্স প্রয়োগ করা যেতে পারে
3. ক্যাপচারিত মান। আপনি যা ক্যাপচার করতে পারবেন না
3.1। আপনি কেবল স্থানীয় যুদ্ধগুলি ক্যাপচার করতে পারেন, অবজেক্টের সদস্য ভেরিয়েবল নয়।
4. রূপান্তর
৪.১ !! লাম্বদা কোনও ফাংশন পয়েন্টার নয় এবং এটি কোনও নামহীন ফাংশন নয়, তবে ক্যাপচার-কম ল্যাম্বডাস স্পষ্টভাবে কোনও ফাংশন পয়েন্টারে রূপান্তরিত হতে পারে।
পুনশ্চ
লাম্বদা ব্যাকরণ সম্পর্কিত আরও তথ্য প্রোগ্রামিং ল্যাঙ্গুয়েজ সি ++ # 337, 2012-01-16, 5.1.2 এর ওয়ার্কিং ড্রাফ্টে পাওয়া যাবে। লাম্বদা এক্সপ্রেশন, পৃষ্ঠা ৮৮
সি ++ ১৪-তে অতিরিক্ত বৈশিষ্ট্য যা "আর্ট ক্যাপচার" হিসাবে যুক্ত হয়েছে যুক্ত করা হয়েছে। এটি ক্লোজার ডেটা সদস্যদের ইচ্ছামত ঘোষণা সম্পাদনের অনুমতি দেয়:
auto toFloat = [](int value) { return float(value);};
auto interpolate = [min = toFloat(0), max = toFloat(255)](int value)->float { return (value - min) / (max - min);};
[&,=Param2](int arg1){}
বৈধ সিনট্যাক্স বলে মনে হচ্ছে না। সঠিক ফর্মটি হবে[&,Param2](int arg1){}
একটি ল্যাম্বডা ফাংশন হ'ল একটি অনামী ফাংশন যা আপনি ইন-লাইন তৈরি করেন। কেউ কেউ যেমন ব্যাখ্যা করেছেন, তেমন ভেরিয়েবল ক্যাপচার করতে পারে (যেমন: http://www.stroustrup.com/C++11FAQ.html#lambda ) তবে কিছু সীমাবদ্ধতা রয়েছে are উদাহরণস্বরূপ, যদি এখানে কলব্যাক ইন্টারফেস থাকে তবে,
void apply(void (*f)(int)) {
f(10);
f(20);
f(30);
}
আপনি নীচে প্রয়োগ করার মতো পাসের মতো এটি ব্যবহার করতে স্পটটিতে একটি ফাংশন লিখতে পারেন:
int col=0;
void output() {
apply([](int data) {
cout << data << ((++col % 10) ? ' ' : '\n');
});
}
তবে আপনি এটি করতে পারবেন না:
void output(int n) {
int col=0;
apply([&col,n](int data) {
cout << data << ((++col % 10) ? ' ' : '\n');
});
}
সি ++ 11 স্ট্যান্ডার্ডের সীমাবদ্ধতার কারণে। আপনি ক্যাপচার ব্যবহার করতে চাইলে আপনাকে লাইব্রেরির উপর নির্ভর করতে হবে এবং
#include <functional>
(বা অন্য কোনও এসটিএল লাইব্রেরি যেমন পরোক্ষভাবে এটি পেতে অ্যালগরিদমের মতো) এবং তারপরে এই জাতীয় প্যারামিটার হিসাবে সাধারণ ফাংশনগুলি পাস করার পরিবর্তে std :: ফাংশন নিয়ে কাজ করুন:
#include <functional>
void apply(std::function<void(int)> f) {
f(10);
f(20);
f(30);
}
void output(int width) {
int col;
apply([width,&col](int data) {
cout << data << ((++col % width) ? ' ' : '\n');
});
}
apply
কোনও টেমপ্লেট
শ্রেষ্ঠ ব্যাখ্যা এক lambda expression
সি ++ এর লেখক থেকে দেওয়া হয় বিয়ারনে স্ট্রোভস্ট্রুপের তাঁর পুস্তক ***The C++ Programming Language***
অধ্যায় 11 ( আইএসবিএন-13: 978-0321563842 ):
What is a lambda expression?
একটি ল্যাম্বডা এক্সপ্রেশন , কখনও কখনও ল্যাম্বডা ফাংশন হিসাবেও পরিচিত হয় (বা কঠোরভাবে ভুলভাবে কথা বললে, তবে কথোপকথনভাবে) একটি ল্যাম্বদা হিসাবে পরিচিত , এটি একটি বেনাম ফাংশন অবজেক্টটি সংজ্ঞায়িত এবং ব্যবহার করার জন্য একটি সরল স্বরলিপি । অপারেটর () দিয়ে নামযুক্ত শ্রেণি সংজ্ঞা দেওয়ার পরিবর্তে পরে সেই শ্রেণীর একটি বস্তু তৈরি করা এবং অবশেষে এটি চাওয়া, আমরা একটি শর্টহ্যান্ড ব্যবহার করতে পারি।
When would I use one?
এটি বিশেষত কার্যকর যখন আমরা একটি অ্যালগরিদমের আর্গুমেন্ট হিসাবে কোনও অপারেশনটি পাস করতে চাই। গ্রাফিকাল ইউজার ইন্টারফেস (এবং অন্য কোথাও) এর প্রসঙ্গে, এই ধরনের ক্রিয়াকলাপগুলি প্রায়শই কলব্যাক হিসাবে পরিচিত ।
What class of problem do they solve that wasn't possible prior to their introduction?
এখানে আমি অনুমান করি ল্যাম্বডা এক্সপ্রেশন দিয়ে করা প্রতিটি ক্রিয়াকলাপ এগুলি ছাড়া সমাধান করা যেতে পারে তবে অনেক বেশি কোড এবং অনেক বড় জটিলতার সাথে। লাম্বডা এক্সপ্রেশন এটি আপনার কোডের জন্য অনুকূলিতকরণের উপায় এবং এটিকে আরও আকর্ষণীয় করে তোলার একটি উপায়। স্ট্রোস্টআপের মতো দুঃখজনক:
অনুকূলকরণ কার্যকর উপায়
Some examples
ল্যাম্বদা এক্সপ্রেশন মাধ্যমে
void print_modulo(const vector<int>& v, ostream& os, int m) // output v[i] to os if v[i]%m==0
{
for_each(begin(v),end(v),
[&os,m](int x) {
if (x%m==0) os << x << '\n';
});
}
বা ফাংশন মাধ্যমে
class Modulo_print {
ostream& os; // members to hold the capture list int m;
public:
Modulo_print(ostream& s, int mm) :os(s), m(mm) {}
void operator()(int x) const
{
if (x%m==0) os << x << '\n';
}
};
অথবা এমনকি
void print_modulo(const vector<int>& v, ostream& os, int m)
// output v[i] to os if v[i]%m==0
{
class Modulo_print {
ostream& os; // members to hold the capture list
int m;
public:
Modulo_print (ostream& s, int mm) :os(s), m(mm) {}
void operator()(int x) const
{
if (x%m==0) os << x << '\n';
}
};
for_each(begin(v),end(v),Modulo_print{os,m});
}
আপনার যদি প্রয়োজন হয় তবে lambda expression
নীচের মত নাম লিখতে পারেন :
void print_modulo(const vector<int>& v, ostream& os, int m)
// output v[i] to os if v[i]%m==0
{
auto Modulo_print = [&os,m] (int x) { if (x%m==0) os << x << '\n'; };
for_each(begin(v),end(v),Modulo_print);
}
বা অন্য একটি সাধারণ নমুনা ধরে নিই
void TestFunctions::simpleLambda() {
bool sensitive = true;
std::vector<int> v = std::vector<int>({1,33,3,4,5,6,7});
sort(v.begin(),v.end(),
[sensitive](int x, int y) {
printf("\n%i\n", x < y);
return sensitive ? x < y : abs(x) < abs(y);
});
printf("sorted");
for_each(v.begin(), v.end(),
[](int x) {
printf("x - %i;", x);
}
);
}
পরবর্তী উত্পন্ন করা হবে
0
1
0
1
0
1
0
1
0
1
0 सॉোর্টেক্স - 1; এক্স - 3; এক্স - 4; এক্স - 5; এক্স - 6; এক্স - 7; এক্স - 33;
[]
- এটি হ'ল ক্যাপচার তালিকা বা lambda introducer
: যদি lambdas
তাদের স্থানীয় পরিবেশে অ্যাক্সেসের প্রয়োজন না হয় তবে আমরা এটি ব্যবহার করতে পারি।
বইয়ের উদ্ধৃতি:
ল্যাম্বডা এক্সপ্রেশনটির প্রথম চরিত্রটি সর্বদা [ । একটি ল্যাম্বডা পরিচিতি বিভিন্ন রূপ নিতে পারে:
• [] : একটি খালি ক্যাপচার তালিকা। এটি বোঝায় যে ল্যাম্বডা শরীরে আশেপাশের প্রসঙ্গ থেকে কোনও স্থানীয় নাম ব্যবহার করা যায় না। যেমন ল্যাম্বডা এক্সপ্রেশন জন্য, তথ্য আর্গুমেন্ট বা ননলোকাল ভেরিয়েবল থেকে প্রাপ্ত করা হয়।
• [&] : স্পষ্টভাবে রেফারেন্স দ্বারা ক্যাপচার। সমস্ত স্থানীয় নাম ব্যবহার করা যেতে পারে। সমস্ত স্থানীয় ভেরিয়েবলগুলি রেফারেন্স দ্বারা অ্যাক্সেস করা হয়।
। [=] : স্পষ্টভাবে মান দ্বারা ক্যাপচার। সমস্ত স্থানীয় নাম ব্যবহার করা যেতে পারে। সমস্ত নাম ল্যাম্বডা এক্সপ্রেশনের কল পয়েন্টে নেওয়া স্থানীয় ভেরিয়েবলের অনুলিপিগুলিকে বোঝায়।
• [ক্যাপচার-তালিকা]: সুস্পষ্ট ক্যাপচার; ক্যাপচার-তালিকা হ'ল স্থানীয় ভেরিয়েবলের নামের তালিকা যা রেফারেন্স বা মান দ্বারা ক্যাপচার করা হবে (অর্থাত্ বস্তুতে সঞ্চিত)। এর পূর্বে থাকা নামগুলির সাথে ভেরিয়েবলগুলি এবং রেফারেন্স দ্বারা ক্যাপচার করা হয়। অন্যান্য ভেরিয়েবলগুলি মান দ্বারা ক্যাপচার করা হয়। একটি ক্যাপচার তালিকায় এটি এবং নামগুলি ... উপাদান হিসাবে অনুসরণ করে।
• [&, ক্যাপচার-তালিকা] : তালিকাতে উল্লেখ করা হয়নি এমন নামগুলির সাথে সমস্ত স্থানীয় ভেরিয়েবলকে স্পষ্টতই ক্যাপচার করুন। ক্যাপচার তালিকায় এটি থাকতে পারে। তালিকাভুক্ত নামগুলি & এর আগে দেওয়া যাবে না। ক্যাপচার তালিকায় নামযুক্ত ভেরিয়েবলগুলি মান দ্বারা ক্যাপচার করা হয়।
• [=, ক্যাপচার-তালিকা] : তালিকাতে উল্লেখ নেই এমন নাম সহ সমস্ত স্থানীয় ভেরিয়েবলকে মান দ্বারা স্পষ্টত ক্যাপচার করুন। ক্যাপচার তালিকায় এটি থাকতে পারে না। তালিকাভুক্ত নামগুলি অবশ্যই & এর আগে হওয়া উচিত। ক্যাপচার তালিকায় নামযুক্ত ভেরিয়েবলগুলি রেফারেন্সের মাধ্যমে ক্যাপচার করা হয়।
নোট করুন যে & এর পূর্বে একটি স্থানীয় নাম সর্বদা রেফারেন্স দ্বারা ক্যাপচার করা হয় এবং একটি স্থানীয় নাম সর্বদা মান দ্বারা ক্যাপচার করা হয়। শুধুমাত্র রেফারেন্স দ্বারা ক্যাপচার কলিং পরিবেশে পরিবর্তনশীল পরিবর্তন করতে দেয়।
Additional
Lambda expression
বিন্যাস
অতিরিক্ত রেফারেন্স:
for (int x : v) { if (x % m == 0) os << x << '\n';}
ওয়েল, আমি যে ব্যবহারিক ব্যবহারটি আবিষ্কার করেছি তা হ'ল বয়লার প্লেট কোড হ্রাস করা। উদাহরণ স্বরূপ:
void process_z_vec(vector<int>& vec)
{
auto print_2d = [](const vector<int>& board, int bsize)
{
for(int i = 0; i<bsize; i++)
{
for(int j=0; j<bsize; j++)
{
cout << board[bsize*i+j] << " ";
}
cout << "\n";
}
};
// Do sth with the vec.
print_2d(vec,x_size);
// Do sth else with the vec.
print_2d(vec,y_size);
//...
}
ল্যাম্বদা ছাড়া আপনার বিভিন্ন bsize
ক্ষেত্রে কিছু করার প্রয়োজন হতে পারে । অবশ্যই আপনি একটি ফাংশন তৈরি করতে পারেন তবে আপনি যদি আত্মার ব্যবহারকারীর কার্যকারিতার মধ্যে ব্যবহারকে সীমাবদ্ধ করতে চান তবে কী করবেন? ল্যাম্বডা প্রকৃতি এই প্রয়োজনীয়তা পূরণ করে এবং আমি এই ক্ষেত্রে এটি ব্যবহার করি।
সি ++ এ থাকা ল্যাম্বডাটিকে "গো উপলভ্য ফাংশনটিতে" হিসাবে বিবেচনা করা হয়। হ্যাঁ এটিতে আক্ষরিক অর্থে, আপনি এটি সংজ্ঞায়িত করেন; এটা ব্যবহার করো; এবং পিতামাতার ফাংশন স্কোপ শেষ হওয়ার সাথে সাথে ল্যাম্বদা ফাংশনটি শেষ হয়ে যায়।
সি ++ এটি সি ++ 11 এ উপস্থাপন করেছে এবং প্রত্যেকে এটি প্রতিটি সম্ভাব্য স্থানে পছন্দ করে। উদাহরণ এবং ল্যাম্বদা কী তা এখানে পাওয়া যাবে https://en.cppreferences.com/w/cpp/language/lambda
আমি বর্ণনা করব যা সেখানে নেই তবে প্রতিটি সি ++ প্রোগ্রামারের জন্য জানা অপরিহার্য
ল্যাম্বদা সর্বত্র ব্যবহারের জন্য বোঝানো হয় না এবং প্রতিটি ফাংশন ল্যাম্বডায় প্রতিস্থাপন করা যায় না। এটি সাধারণ ফাংশনের সাথে তুলনা করা দ্রুততমও নয়। কারণ এর কিছু ওভারহেড রয়েছে যা ল্যাম্বডা দ্বারা পরিচালিত হওয়া দরকার।
এটি অবশ্যই কিছু ক্ষেত্রে লাইনের সংখ্যা হ্রাস করতে সহায়তা করবে। এটি মূলত কোড বিভাগের জন্য ব্যবহার করা যেতে পারে, যা একই ফাংশনে এক বা একাধিক সময় কল হয়ে আসছে এবং কোডটির এই অংশটি অন্য কোথাও প্রয়োজন নেই যাতে আপনি এটির জন্য স্বতন্ত্র ফাংশন তৈরি করতে পারেন।
নীচে ল্যাম্বদা এবং পটভূমিতে কী ঘটে যায় তার প্রাথমিক উদাহরণ।
ব্যবহারকারী কোড:
int main()
{
// Lambda & auto
int member=10;
auto endGame = [=](int a, int b){ return a+b+member;};
endGame(4,5);
return 0;
}
সংকলন এটি কীভাবে প্রসারিত করে:
int main()
{
int member = 10;
class __lambda_6_18
{
int member;
public:
inline /*constexpr */ int operator()(int a, int b) const
{
return a + b + member;
}
public: __lambda_6_18(int _member)
: member{_member}
{}
};
__lambda_6_18 endGame = __lambda_6_18{member};
endGame.operator()(4, 5);
return 0;
}
যাতে আপনি দেখতে পাচ্ছেন, আপনি এটি ব্যবহার করার সময় এটি কোন ধরণের ওভারহেড যুক্ত করে। সুতরাং এগুলি সর্বত্র ব্যবহার করা ভাল ধারণা নয়। এটি যেখানে প্রযোজ্য সেখানে এটি ব্যবহার করা যেতে পারে।
এটি সমাধান করে এমন একটি সমস্যা: কনস্ট্রাক্টরের কল করার জন্য ল্যাম্বডা থেকে কোড সহজ যা কোনও কনস্টের সদস্যকে আরম্ভ করার জন্য আউটপুট প্যারামিটার ফাংশন ব্যবহার করে
আপনি কোনও আউটপুট প্যারামিটার হিসাবে তার আউটপুট ফিরিয়ে দিয়ে এর মান নির্ধারণ করে এমন একটি ফাংশনে কল দিয়ে আপনার ক্লাসের একজন কনস্ট সদস্যকে সূচনা করতে পারেন।