আমি এরকম কিছু বোঝাতে চাইছি:
int main()
{
void a()
{
// code
}
a();
return 0;
}
আমি এরকম কিছু বোঝাতে চাইছি:
int main()
{
void a()
{
// code
}
a();
return 0;
}
উত্তর:
সি ++ (সি ++ 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";
}
}
সি ++ সরাসরি এটি সমর্থন করে না।
এটি বলেছিল, আপনার স্থানীয় ক্লাস থাকতে পারে এবং তাদের ফাংশন থাকতে পারে (অ- staticবা static), তাই আপনি এটি কিছুটা বর্ধিত করতে পারেন, যদিও এটি কিছুটা ক্লডজের কিছুটা হলেও:
int main() // it's int, dammit!
{
struct X { // struct's as good as class
static void a()
{
}
};
X::a();
return 0;
}
যাইহোক, আমি প্রক্সীদের প্রশ্ন করব। প্রত্যেকেই জানেন (ভাল, এখন আপনি যেভাবেই করেন :)) সি ++ স্থানীয় ফাংশনগুলি সমর্থন করে না, তাই তারা সেগুলি না রাখার জন্য অভ্যস্ত। সেগুলি অবশ্য সেই কাদলে ব্যবহৃত হয় না। স্থানীয় কোডগুলি ব্যবহারের অনুমতি দেওয়ার জন্য এটি কেবল সেখানে রয়েছে তা নিশ্চিত করার জন্য আমি এই কোডটিতে বেশ কিছুটা সময় ব্যয় করব। ভাল না.
int main()এবংint main(int argc, char* argv[])
int main()এবং int main(int argc, char* argv[])অবশ্যই সমর্থিত হবে এবং অন্যদের সমর্থন করা যেতে পারে তবে সেগুলি সবগুলিই ফিরে এসেছে।
সমস্ত উদ্দেশ্য এবং উদ্দেশ্যে, সি ++ ল্যাম্বডাসের মাধ্যমে এটি সমর্থন করে : 1
int main() {
auto f = []() { return 42; };
std::cout << "f() = " << f() << std::endl;
}
এখানে, fএকটি ল্যাম্বডা অবজেক্ট যা স্থানীয় ফাংশন হিসাবে কাজ করে main। স্থানীয় জিনিসগুলিতে অ্যাক্সেস করার জন্য ক্যাপচারগুলি নির্দিষ্ট করা যেতে পারে।
পর্দার আড়ালে, fএকটি ফাংশন অবজেক্ট (যেমন একটি প্রকারের একটি বস্তু যা সরবরাহ করে operator())। ল্যাম্বদার উপর ভিত্তি করে ফাংশন অবজেক্টের ধরণটি সংকলক দ্বারা তৈরি করা হয়েছে।
সি ++ 11 সাল থেকে 1
+1থেকে আমার থেকে অনেক ভাল better
স্থানীয় ক্লাসগুলি ইতিমধ্যে উল্লেখ করা হয়েছে, তবে এখানে অপারেটর () ওভারলোড এবং একটি বেনামী ক্লাস ব্যবহার করে স্থানীয় ফাংশন হিসাবে তাদের আরও বেশি প্রদর্শিত হওয়ার উপায় এখানে:
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 উচিত নয়)।
কিছুক্ষণ আগে সি ++ 11 এর উত্থানের সাথে আপনার এখন স্থানীয় ফাংশন থাকতে পারে যার বাক্য গঠনটি জাভাস্ক্রিপ্টের সাথে একটু স্মরণীয়:
auto fac = [] (unsigned int val) {
return val*42;
};
operator () (unsigned int val), আপনার বন্ধনীর একটি সেট মিস করা।
std::sort(), বাতে যেতে std::for_each()।
autoভেরিয়েবল ঘোষণার জন্য ব্যবহার করতে পারবেন না । স্ট্রাস্ট্রাপ উদাহরণ দেয়: function<void(char*b, char*e)> rev=[](char*b, char*e) { if( 1<e-b ) { swap( *b, *--e); rev(++b,e); } };প্রদত্ত স্ট্রিংটি শুরু এবং শেষের পয়েন্টারগুলিকে বিপরীত করার জন্য।
না।
আপনি কি করতে চেষ্টা করছেন?
কার্যসংক্রান্ত:
int main(void)
{
struct foo
{
void operator()() { int a = 1; }
};
foo b;
b(); // call the operator()
}
সি ++ 11 দিয়ে শুরু করে আপনি সঠিক ল্যাম্বডাস ব্যবহার করতে পারেন । আরও তথ্যের জন্য অন্যান্য উত্তর দেখুন।
পুরানো উত্তর: আপনি বাছাই করতে পারেন, তবে আপনাকে ঠকানো এবং একটি ডামি ক্লাস ব্যবহার করতে হবে:
void moo()
{
class dummy
{
public:
static void a() { printf("I'm in a!\n"); }
};
dummy::a();
dummy::a();
}
অন্যরা যেমন উল্লেখ করেছে, আপনি gcc এ gnu ভাষার এক্সটেনশনগুলি ব্যবহার করে নেস্টেড ফাংশনগুলি ব্যবহার করতে পারেন। যদি আপনি (বা আপনার প্রকল্প) জিসিসি টুলচেইনে আটকে থাকেন তবে আপনার কোডটি বেশিরভাগ ক্ষেত্রে জিসিসি সংকলক দ্বারা লক্ষ্যযুক্ত বিভিন্ন আর্কিটেকচার জুড়ে বহনযোগ্য।
তবে, যদি আপনার কোনও অন্য প্রয়োজনীয় সরঞ্জামের প্রয়োজন হয় যে কোনও আলাদা সরঞ্জামচইনের সাহায্যে কোডটি সংকলন করা প্রয়োজন, তবে আমি এই জাতীয় এক্সটেনশনগুলি থেকে দূরে থাকব।
নেস্টেড ফাংশনগুলি ব্যবহার করার সময় আমি যত্ন সহকারে পদক্ষেপও করতাম। জটিল, তবুও কোডের সমন্বয়মূলক ব্লকগুলির কাঠামো পরিচালনার জন্য এগুলি একটি সুন্দর সমাধান (এর টুকরোগুলি বাহ্যিক / সাধারণ ব্যবহারের জন্য নয়) এটি নেমস্পেস দূষণ নিয়ন্ত্রণেও খুব সহায়ক (প্রাকৃতিক জটিল / একটি অত্যন্ত বাস্তব উদ্বেগ) ভার্বোজ ভাষায় দীর্ঘ ক্লাস।)
তবে যে কোনও কিছুর মতো এগুলি আপত্তিজনকভাবে উন্মুক্ত থাকতে পারে।
এটি দুঃখজনক যে সি / সি ++ স্ট্যান্ডার্ড হিসাবে এই জাতীয় বৈশিষ্ট্যগুলি সমর্থন করে না। বেশিরভাগ প্যাস্কাল ভেরিয়েন্ট এবং অ্যাডা ডো (প্রায় সমস্ত আলগোল ভিত্তিক ভাষাগুলিই করে)। জাভাস্ক্রিপ্ট একই। স্কালার মতো আধুনিক ভাষার সাথেও। এর্লং, লিস্প বা পাইথনের মতো শ্রদ্ধেয় ভাষার সাথে একই।
এবং ঠিক যেমন সি / সি ++ এর সাথে, দুর্ভাগ্যক্রমে, জাভা (যা দিয়ে আমি আমার বেশিরভাগ জীবন উপার্জন করি) তা করে না।
আমি এখানে জাভা উল্লেখ করেছি কারণ আমি বেশ কয়েকটি পোস্টার দেখতে পেয়েছি যাতে নেস্টেড ফাংশনগুলির বিকল্প হিসাবে ক্লাস এবং ক্লাসের পদ্ধতি ব্যবহারের পরামর্শ দেওয়া হচ্ছে। এবং এটি জাভাতে সাধারণ কাজও নয়।
সংক্ষিপ্ত উত্তর: না
এটি করার ফলে শ্রেণিবদ্ধ শ্রেণিতে কৃত্রিম, অযথা জটিলতার পরিচয় দেওয়া হয়। সমস্ত জিনিস সমান হওয়ার সাথে সাথে আদর্শটি হ'ল একটি শ্রেণিবদ্ধ স্তর (এবং এর অন্তর্ভুক্ত নেমস্পেস এবং স্কোপস) যথাসম্ভব সহজ একটি বাস্তব ডোমেনকে উপস্থাপন করা।
নেস্টেড ফাংশনগুলি "ব্যক্তিগত", কার্যকারিতা জটিলতার সাথে ডিল করতে সহায়তা করে। এই সুবিধার অভাবের কারণে, সেই "ব্যক্তিগত" জটিলতার প্রচার এবং নিজের শ্রেণির মডেলটিকে প্রচার করা এড়ানো উচিত।
সফ্টওয়্যার (এবং যে কোনও ইঞ্জিনিয়ারিং বিভাগে), মডেলিং ট্রেড অফের বিষয়। সুতরাং, বাস্তব জীবনে, এই নিয়মগুলির (বা বরং নির্দেশিকা) যথাযথ ব্যতিক্রম হবে। যত্ন সহকারে এগিয়ে যান, যদিও।
সি ++ এ আপনার স্থানীয় ফাংশন থাকতে পারে না। তবে সি ++ 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;
}
না, এটি অনুমোদিত নয়। সি বা সি ++ উভয়ই ডিফল্টরূপে এই বৈশিষ্ট্যটিকে সমর্থন করে না, তবে টনিক (মন্তব্যগুলিতে) উল্লেখ করেছেন যে জিএনইউ সি সংকলকটির এক্সটেনশন রয়েছে যা সিতে এই আচরণকে সক্ষম করে enable
এই সমস্ত কৌশলগুলি কেবল স্থানীয় ফাংশন হিসাবে দেখায় (কম বা কম) তবে তারা সেভাবে কাজ করে না। স্থানীয় ফাংশনে আপনি এর সুপার ফাংশনগুলির স্থানীয় ভেরিয়েবলগুলি ব্যবহার করতে পারেন। এটি একধরনের সেমি-গ্লোবাল। এই কৌশলগুলি না করে এটি করতে পারে। নিকটতমটি সি ++ 0 এক্স থেকে ল্যাম্বডা ট্রিক, তবে এটি বন্ধ হওয়ার সময় সংজ্ঞায়নের সময় আবদ্ধ, ব্যবহারের সময় নয়।
আপনি অন্য + এর ভিতরে ফ্রি ফাংশনটি সি ++ এ সংজ্ঞায়িত করতে পারবেন না।
আমি এখানে 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;
}
(*) সি ++ বিশ্বে ম্যাক্রো ব্যবহার করে কখনই পরিষ্কার বলে বিবেচিত হয় না।
তবে আমরা মূল () এর ভিতরে কোনও ফাংশন ঘোষণা করতে পারি:
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());
}
=> কোনও প্রোগ্রাম আউটপুট নেই।
(সংকলনের পরে কেবল কলঙ্কের সতর্কতা)।