std::for_eachওভার forলুপের কোনও সুবিধা আছে কি? আমার কাছে std::for_eachকেবল কোডের পঠনযোগ্যতাকেই বাধা বলে মনে হচ্ছে। তাহলে কেন কিছু কোডিং মান তার ব্যবহারের পরামর্শ দেয়?
std::for_eachওভার forলুপের কোনও সুবিধা আছে কি? আমার কাছে std::for_eachকেবল কোডের পঠনযোগ্যতাকেই বাধা বলে মনে হচ্ছে। তাহলে কেন কিছু কোডিং মান তার ব্যবহারের পরামর্শ দেয়?
উত্তর:
সি ++ 11 (যা আগে সি ++ 0x নামে পরিচিত) সহ সুন্দর জিনিসটি হ'ল এই ক্লান্তিকর বিতর্ক নিষ্পত্তি হবে।
আমি বলতে চাইছি, তাদের সঠিক মনের কেউ নেই, যিনি পুরো সংগ্রহটি নিয়ে পুনরাবৃত্তি করতে চান, তারা এখনও এটি ব্যবহার করবেন না
for(auto it = collection.begin(); it != collection.end() ; ++it)
{
foo(*it);
}
অথবা এটা
for_each(collection.begin(), collection.end(), [](Element& e)
{
foo(e);
});
যখন পরিসীমা ভিত্তিক forলুপ সিনট্যাক্স উপলব্ধ থাকে:
for(Element& e : collection)
{
foo(e);
}
জাভা এবং সি # তে এই জাতীয় সিনট্যাক্সটি বেশ কিছু সময়ের জন্য উপলভ্য ছিল এবং আমি দেখলাম প্রতিটি সাম্প্রতিক জাভা বা সি # কোডে foreachশাস্ত্রীয় forলুপের চেয়ে আরও বেশি লুপ রয়েছে ।
Element & eহিসাবে auto & e(অথবা auto const &e) ভাল দেখায়। আমি Element const eঅন্তর্নিহিত রূপান্তর চাইলে আমি (রেফারেন্স ছাড়াই) ব্যবহার করব, উত্সটি যখন বিভিন্ন ধরণের সংকলন হয় এবং আমি সেগুলিতে রূপান্তর করতে চাই Element।
এখানে কিছু কারণ রয়েছে:
এটি পড়ার ক্ষমতা বাধা বলে মনে হচ্ছে কারণ আপনি এটি ব্যবহার করেন না এবং / বা এটি সত্যই সহজ করার জন্য তার চারপাশে সঠিক সরঞ্জামগুলি ব্যবহার করছেন না। (সহায়তাকারীদের জন্য বুস্ট :: রেঞ্জ এবং বুস্ট :: বাইন্ড / বুস্ট :: ল্যাম্বদা দেখুন these এর মধ্যে অনেকগুলি সি ++ 0x এ চলে যাবে এবং for_each এবং সম্পর্কিত ফাংশনগুলিকে আরও দরকারী করে তুলবে))
এটি আপনাকে for_each এর উপরে একটি অ্যালগরিদম লিখতে দেয় যা কোনও পুনরুক্তিকারীর সাথে কাজ করে।
এটি নির্বোধ টাইপিং বাগের সম্ভাবনা হ্রাস করে।
এছাড়া STL-আলগোরিদিম মত বাকি আপনার মন খোলে find_if, sort, replace, ইত্যাদি এবং এই আর এত অদ্ভুত অদ্ভুত চেহারা করা হবে না। এটি বিশাল জয় হতে পারে।
আপডেট 1:
সবচেয়ে গুরুত্বপূর্ণ, এটি আপনাকে ছাড়িয়ে যেতে সহায়তা করে for_each বনাম-লুপগুলি যা এখানে রয়েছে, এবং অন্যান্য এসটিএল-অলোগগুলি, যেমন সন্ধান / সাজানো / পার্টিশন / অনুলিপি_পরিবর্তন_ফ, সমান্তরাল সম্পাদন .. বা যাই হোক না কেন দেখুন।
For_each ভাইবোনদের "বাকী" ব্যবহার করে প্রচুর প্রসেসিং খুব সংক্ষিপ্তভাবে লেখা যেতে পারে, তবে আপনি যদি সমস্ত কিছু করেন তবে বিভিন্ন অভ্যন্তরীণ যুক্তি সহ একটি লুপ লেখার জন্য, তবে আপনি সেগুলি কীভাবে ব্যবহার করবেন তা কখনই শিখবেন না এবং আপনি চাকাটি বারবার আবিষ্কার করা শেষ করুন।
এবং (শিগগিরই_আচের জন্য উপলব্ধ পরিসীমা শৈলী):
for_each(monsters, boost::mem_fn(&Monster::think));
অথবা সি ++ এক্স 11 ল্যাম্বডাস সহ:
for_each(monsters, [](Monster& m) { m.think(); });
আইএমও এর চেয়ে বেশি পঠনযোগ্য:
for(Monsters::iterator i = monsters.begin(); i != monsters.end(); ++i) {
i->think();
}
এছাড়াও এটি (বা ল্যাম্বডাস সহ অন্যদের দেখুন):
for_each(bananas, boost::bind(&Monkey::eat, my_monkey, _1));
এর চেয়ে আরও সংক্ষিপ্ত:
for(Bananas::iterator i = bananas.begin(); i != bananas.end(); ++i) {
my_monkey->eat(*i);
}
বিশেষত যদি কল করার জন্য আপনার বেশ কয়েকটি ফাংশন থাকে ... তবে সম্ভবত এটি কেবল আমার। ;)
আপডেট 2 : আমি আমার নিজের স্টাইল-অ্যালগোসের ওয়ান-লাইনার মোড়কগুলি লিখেছি যা পুনরাবৃত্তির জুটির পরিবর্তে রেঞ্জগুলির সাথে কাজ করে। বুস্ট :: রেঞ্জ_েক্স, একবার প্রকাশিত হলে এটি অন্তর্ভুক্ত করবে এবং সম্ভবত এটি C ++ 0x তেও থাকবে?
outer_class::inner_class::iteratorবা এগুলি টেমপ্লেট আর্গুমেন্ট: typename std::vector<T>::iterator... কনস্ট্রাক্টের জন্য নিজেই অনেকগুলি লাইন কনস্ট্রাক্টের মধ্যে চলে যেতে পারে
for_eachদ্বিতীয় উদাহরণটির মধ্যে for_each( bananas.begin(), bananas.end(),...
for_eachআরও জেনেরিক। আপনি এটিকে যেকোন প্রকারের ধারক (সূচনা / শেষ পুনরাবৃত্তকারীগুলিতে পাস করে) পুনরাবৃত্তি করতে ব্যবহার করতে পারেন। আপনি for_eachপুনরাবৃত্তি কোডটি আপডেট না করেই কোনও ফাংশনটির নীচে কনটেইনারগুলি সরিয়ে আউট করতে পারেন । আপনার বিবেচনার জন্য চেয়ে বিশ্বের অন্যান্য পাত্রে আছে প্রয়োজন std::vectorএবং প্লেইন পুরাতন সি অ্যারে সুবিধার দেখতে for_each।
এর প্রধান অসুবিধা for_eachহ'ল এটি একটি ফান্টার লাগে, তাই বাক্য গঠনটি আটকানো। লাম্বদা প্রবর্তনের সাথে এটি সি ++ 11 (পূর্বে সি ++ 0x) এ স্থির করা হয়েছে:
std::vector<int> container;
...
std::for_each(container.begin(), container.end(), [](int& i){
i+= 10;
});
এটি আপনার কাছে 3 বছরের মধ্যে অদ্ভুত লাগবে না।
for ( int v : int_vector ) {(যদিও এটি আজ বোসT_ফোরাকের সাথে অনুকরণ করা যায়)
std::for_each(container, [](int& i){ ... });। আমি বোঝাতে চাইছি কেন একজন কেন দু'বার কন্টেইনার লিখতে বাধ্য?
container.each { ... }শুরু এবং শেষ পুনরাবৃত্তির উল্লেখ না করেই এমন কিছু লেখেন । আমি এটি কিছুটা রিডানড্যান্ট পেয়েছি যা আমাকে সর্বদা শেষ পুনরুক্তি নির্দিষ্ট করতে হবে।
ব্যক্তিগতভাবে, যে কোনও সময় আমার ব্যবহারের বাইরে যেতে হবে std::for_each(বিশেষ-উদ্দেশ্যযুক্ত ফান্টেক্টর / জটিল boost::lambdaগুলি লিখুন), আমি খুঁজে পেয়েছি BOOST_FOREACHএবং সি ++ 0x এর পরিসর ভিত্তিক পরিষ্কারের জন্য:
BOOST_FOREACH(Monster* m, monsters) {
if (m->has_plan())
m->act();
}
বনাম
std::for_each(monsters.begin(), monsters.end(),
if_then(bind(&Monster::has_plan, _1),
bind(&Monster::act, _1)));
এটির বিষয়ভিত্তিক, কেউ কেউ বলবেন যে কোডগুলি ব্যবহার for_each করে কোডটি আরও পঠনযোগ্য হয়ে উঠবে , কারণ এটি একই সম্মেলনের মাধ্যমে বিভিন্ন সংগ্রহের চিকিত্সার অনুমতি দেয়।
for_eachitlef লুপ হিসাবে প্রয়োগ করা হয়
template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f)
{
for ( ; first!=last; ++first ) f(*first);
return f;
}
সুতরাং আপনার পক্ষে সঠিক কি তা চয়ন করা আপনার পক্ষে।
অনেক অ্যালগরিদম ফাংশনের মতো, একটি প্রাথমিক প্রতিক্রিয়া হ'ল ভাবা যে লুপের চেয়ে ফোরচ ব্যবহার করা আরও অপঠনযোগ্য। এটি অনেক শিখা যুদ্ধের একটি বিষয় ছিল।
আপনি একবার মূর্ছনায় অভ্যস্ত হয়ে উঠলে এটি আপনাকে দরকারী মনে হতে পারে। একটি সুস্পষ্ট সুবিধা হ'ল এটি কোডারটিকে লুপের অভ্যন্তরীণ সামগ্রীগুলি প্রকৃত পুনরাবৃত্তির কার্যকারিতা থেকে আলাদা করতে বাধ্য করে। (ঠিক আছে, আমি এটি একটি সুবিধা বলে মনে করি Other অন্যরা বলে যে আপনি কোনও সত্যিকারের বেনিফিট ছাড়াই কোডটি কাটাচ্ছেন)।
অন্য একটি সুবিধা হ'ল আমি যখন ফোরচ দেখি তখন আমি জানি যে প্রতিটি আইটেমই প্রক্রিয়াজাত করা হবে বা একটি ব্যতিক্রম নিক্ষেপ করা হবে।
একটি জন্য লুপ লুপ সসীম জন্য বিভিন্ন বিকল্প দেয়। আপনি লুপটিকে তার সম্পূর্ণ কোর্সটি চালিয়ে যেতে দিতে পারেন, বা আপনি স্পষ্টভাবে লুপ থেকে ঝাঁপতে ব্রেক কীওয়ার্ডটি ব্যবহার করতে পারেন বা পুরো ফাংশন মিড-লুপ থেকে প্রস্থান করতে রিটার্ন কীওয়ার্ডটি ব্যবহার করতে পারেন । বিপরীতে, foreach এই বিকল্পগুলির অনুমতি দেয় না এবং এটি এটিকে আরও পঠনযোগ্য করে তোলে। আপনি কেবল ফাংশনটির নামটি দেখতে পারেন এবং আপনি পুনরাবৃত্তির পুরো প্রকৃতিটি জানেন know
লুপের জন্য বিভ্রান্তির উদাহরণ এখানে :
for(std::vector<widget>::iterator i = v.begin(); i != v.end(); ++i)
{
/////////////////////////////////////////////////////////////////////
// Imagine a page of code here by programmers who don't refactor
///////////////////////////////////////////////////////////////////////
if(widget->Cost < calculatedAmountSofar)
{
break;
}
////////////////////////////////////////////////////////////////////////
// And then some more code added by a stressed out juniour developer
// *#&$*)#$&#(#)$#(*$&#(&*^$#(*$#)($*#(&$^#($*&#)$(#&*$&#*$#*)$(#*
/////////////////////////////////////////////////////////////////////////
for(std::vector<widgetPart>::iterator ip = widget.GetParts().begin(); ip != widget.GetParts().end(); ++ip)
{
if(ip->IsBroken())
{
return false;
}
}
}
std::for_each()পুরানো স্ট্যান্ডার্ডটি ব্যবহার করেন (এই পোস্টের সময়ের মতো) আপনাকে একটি নামী ফান্টর ব্যবহার করতে হবে, যা আপনি যেমন বলছেন ততই পাঠযোগ্যতা উত্সাহিত করে এবং অকাল আগে লুপটি ছিন্ন করতে নিষেধ করে। তবে তারপরে সমমানের forলুপটিতে একটি ফাংশন কল ছাড়া কিছুই নেই, এবং এটিও অকালব্যাপী ছড়িয়ে পড়া নিষেধ করে। তবে std::for_each() এগুলি বাদে আমি মনে করি আপনি এটি বলার ক্ষেত্রে একটি দুর্দান্ত পয়েন্ট করেছেন যা পুরো ব্যাপ্তির মধ্য দিয়ে চলেছে।
আপনি বেশিরভাগ ক্ষেত্রেই সঠিক: বেশিরভাগ সময় std::for_eachনিট ক্ষতি হয়। আমি তুলনা for_eachকরতে অনেকদূর যেতে চাই goto। gotoসর্বাধিক বহুমুখী ফ্লো-কন্ট্রোল সরবরাহ করে - আপনি কল্পনা করতে পারেন এমন অন্য কোনও নিয়ন্ত্রণ কাঠামো বাস্তবায়নের জন্য এটি ব্যবহার করতে পারেন। সেই অতি বহুমুখিতাটির অর্থ, gotoবিচ্ছিন্নতা দেখানো আপনাকে এই পরিস্থিতিতে কী করতে হবে তা সম্পর্কে কার্যত কিছুই বলে না। ফলস্বরূপ, তাদের সঠিক মনের প্রায় কেউই gotoসর্বশেষ উপায় হিসাবে ব্যবহার করে না।
স্ট্যান্ডার্ড অ্যালগরিদমগুলির মধ্যে for_eachঅনেকটা একইভাবে - এটি কার্যত যে কোনও কিছুই বাস্তবায়নের জন্য ব্যবহার করা যেতে পারে, যার অর্থ for_eachএই পরিস্থিতিতে এটি কী ব্যবহার করা হচ্ছে তা দেখা আপনাকে কার্যত কিছুই বলে না। দুর্ভাগ্যক্রমে, জনগণের দৃষ্টিভঙ্গি for_eachসম্পর্কে যেখানে তাদের দৃষ্টিভঙ্গি gotoছিল (1970) বা তেমন - কয়েকটি সম্পর্কে toward জন এই সত্যকে ধরে ফেলেছিল যে এটি কেবল একটি শেষ অবলম্বন হিসাবে ব্যবহার করা উচিত, তবে অনেকে এখনও এটিকে প্রাথমিক অ্যালগরিদম হিসাবে বিবেচনা করে এবং খুব কমই যদি কখনও অন্য কোন ব্যবহার। বেশিরভাগ সময়, এমনকি একটি তাত্ক্ষণিক নজরে প্রকাশিত হতে পারে যে বিকল্পগুলির মধ্যে একটি মারাত্মকভাবে উন্নত ছিল।
শুধু উদাহরণস্বরূপ, আমি প্রায় কতবার আমি কোডটি লেখা একটি সংগ্রহ ব্যবহার বিষয়বস্তু প্রিন্ট আউট করতে মানুষ দেখা করেছি ট্র্যাক নিশ্চিত আমি হারিয়ে ফেলেছি আছি for_each। পোস্ট আমি দেখেছি উপর ভিত্তি করে, এই ভাল একক সবচেয়ে প্রচলিত ব্যবহার করা যেতে পারে for_each। এগুলি এমন কিছু দিয়ে শেষ হয়:
class XXX {
// ...
public:
std::ostream &print(std::ostream &os) { return os << "my data\n"; }
};
তাদের পোস্টের কি সমন্বয় সম্পর্কে জিজ্ঞাসা করা হয় bind1st, mem_funইত্যাদি তারা ভালো কিছু করতে প্রয়োজন:
std::vector<XXX> coll;
std::for_each(coll.begin(), coll.end(), XXX::print);
কাজ করুন, এবং এর উপাদানগুলি মুদ্রণ করুন coll। আমি যদি এখানে এটি লিখে রেখেছিলাম ঠিক এটি যদি কাজ করে তবে তা মধ্যযুগীয় হবে, তবে তা হয় না - এবং আপনি যখন এটি কাজ করতে পেরেছেন, তখন কিসের সাথে সম্পর্কিত কোডের কয়েকটি বিট খুঁজে পাওয়া মুশকিল? এটি একসাথে রাখা টুকরাগুলির মধ্যে চলছে।
ভাগ্যক্রমে, আরও অনেক ভাল উপায় আছে। XXX এর জন্য একটি সাধারণ স্ট্রিম সন্নিবেশকারী ওভারলোড যুক্ত করুন:
std::ostream &operator<<(std::ostream *os, XXX const &x) {
return x.print(os);
}
এবং ব্যবহার std::copy:
std::copy(coll.begin(), coll.end(), std::ostream_iterator<XXX>(std::cout, "\n"));
যে কাজ করে - এবং সব সময়ে কার্যত কোন কাজ নেয় জিনিসটা এটি বিষয়বস্তু ছাপে collকরতে std::cout।
boost::mem_fn(&XXX::print)পরিবর্তে হওয়া উচিতXXX::print
std::coutএর যুক্তি হিসাবেও আবদ্ধ করতে হবে)।
বেশি পঠনযোগ্য মৌমাছির জন্য কার্যকরী লেখার সুবিধা, কখন for(...)এবং কখন প্রদর্শিত হবে না for_each(...)।
আপনি যদি ফাংশনাল এইচটিতে সমস্ত অ্যালগরিদম ব্যবহার করেন তবে ফর-লুপগুলি ব্যবহারের পরিবর্তে কোডটি আরও অনেক বেশি পঠনযোগ্য হয়;
iterator longest_tree = std::max_element(forest.begin(), forest.end(), ...);
iterator first_leaf_tree = std::find_if(forest.begin(), forest.end(), ...);
std::transform(forest.begin(), forest.end(), firewood.begin(), ...);
std::for_each(forest.begin(), forest.end(), make_plywood);
এর চেয়ে অনেক বেশি পাঠযোগ্য;
Forest::iterator longest_tree = it.begin();
for (Forest::const_iterator it = forest.begin(); it != forest.end(); ++it{
if (*it > *longest_tree) {
longest_tree = it;
}
}
Forest::iterator leaf_tree = it.begin();
for (Forest::const_iterator it = forest.begin(); it != forest.end(); ++it{
if (it->type() == LEAF_TREE) {
leaf_tree = it;
break;
}
}
for (Forest::const_iterator it = forest.begin(), jt = firewood.begin();
it != forest.end();
it++, jt++) {
*jt = boost::transformtowood(*it);
}
for (Forest::const_iterator it = forest.begin(); it != forest.end(); ++it{
std::makeplywood(*it);
}
এবং এটি আমার কাছে খুব সুন্দর বলে মনে হয়, লুপগুলিকে এক লাইনের ফাংশনে সাধারণকরণ করুন =)
সহজ: for_eachআপনার কাছে ইতিমধ্যে প্রতিটি অ্যারে আইটেম পরিচালনা করার জন্য কোনও ফাংশন রয়েছে এমন সময় কার্যকর হয়, যাতে আপনাকে ল্যাম্বদা লিখতে হবে না। অবশ্যই, এই
for_each(a.begin(), a.end(), a_item_handler);
বেশী ভালো
for(auto& item: a) {
a_item_handler(a);
}
এছাড়াও, forসম্পূর্ণ পাত্রে শুরু থেকে শেষ পর্যন্ত রেঞ্জযুক্ত লুপটি পুনরাবৃত্তি করে, যদিও for_eachআরও নমনীয়।
for_eachলুপ ব্যবহারকারী কোড থেকে iterators (কিভাবে একটি লুপ বাস্তবায়িত হয় এর বিবরণ সহ) লুকান এবং অপারেশন স্পষ্ট শব্দার্থবিদ্যা সংজ্ঞায়িত বোঝানো হয়: প্রতিটি উপাদান ঠিক একবার iterated করা হবে না।
বর্তমান মানটিতে পাঠযোগ্যতার সমস্যাটি হ'ল এতে কোডের ব্লকের পরিবর্তে শেষ যুক্তি হিসাবে একটি ফান্টকারের প্রয়োজন হয়, সুতরাং অনেক ক্ষেত্রে আপনাকে অবশ্যই এটির জন্য নির্দিষ্ট ফান্টার টাইপ লিখতে হবে। এটি কম পঠনযোগ্য কোডে রূপান্তরিত করে কারণ ফান্টর অবজেক্টগুলিকে স্থানে সংজ্ঞায়িত করা যায় না (কোনও ফাংশনের মধ্যে সংজ্ঞায়িত স্থানীয় ক্লাসগুলি টেমপ্লেট আর্গুমেন্ট হিসাবে ব্যবহার করা যায় না) এবং লুপটির বাস্তবায়ন অবশ্যই আসল লুপ থেকে সরে যেতে হবে।
struct myfunctor {
void operator()( int arg1 ) { code }
};
void apply( std::vector<int> const & v ) {
// code
std::for_each( v.begin(), v.end(), myfunctor() );
// more code
}
নোট করুন যে আপনি যদি প্রতিটি বস্তুর উপর একটি নির্দিষ্ট ক্রিয়াকলাপ করতে চান তবে এটি সহজ করতে আপনি ব্যবহার করতে পারেন std::mem_fn, বা boost::bind( std::bindপরবর্তী স্ট্যান্ডার্ডে), বা boost::lambda(পরবর্তী স্ট্যান্ডার্ডে ল্যাম্বডাস) ব্যবহার করতে পারেন:
void function( int value );
void apply( std::vector<X> const & v ) {
// code
std::for_each( v.begin(), v.end(), boost::bind( function, _1 ) );
// code
}
আপনার কাছে কল করার জন্য ফাংশন / পদ্ধতি থাকলে হ্যান্ড রোলড সংস্করণটির চেয়ে কম পঠনযোগ্য এবং বেশি কমপ্যাক্ট নয়। বাস্তবায়ন for_eachলুপের অন্যান্য বাস্তবায়ন সরবরাহ করতে পারে (সমান্তরাল প্রক্রিয়াজাতকরণ ভাবেন)।
আসন্ন মানটি বিভিন্ন উপায়ে কিছু ত্রুটিগুলির যত্ন নেয়, এটি স্থানীয়ভাবে সংজ্ঞায়িত শ্রেণীর জন্য টেমপ্লেটগুলির আর্গুমেন্ট হিসাবে মঞ্জুরি দেয়:
void apply( std::vector<int> const & v ) {
// code
struct myfunctor {
void operator()( int ) { code }
};
std::for_each( v.begin(), v.end(), myfunctor() );
// code
}
কোডের স্থানীয়ত্ব উন্নত করা: আপনি যখন ব্রাউজ করবেন আপনি দেখতে পাবেন যে এটি ঠিক সেখানে কী করছে। প্রকৃতপক্ষে, ফ্যান্ট্যাক্টরটি সংজ্ঞায়িত করতে আপনার ক্লাস সিনট্যাক্স ব্যবহার করার দরকার নেই, তবে এখনই ল্যাম্বডা ব্যবহার করুন:
void apply( std::vector<int> const & v ) {
// code
std::for_each( v.begin(), v.end(),
[]( int ) { // code } );
// code
}
এমনকি যদি for_eachকোনও নির্দিষ্ট নির্মাণ হয় যা এটি আরও প্রাকৃতিক করে তুলবে:
void apply( std::vector<int> const & v ) {
// code
for ( int i : v ) {
// code
}
// code
}
আমি for_eachহ্যান্ড রোলড লুপগুলির সাথে কনস্ট্রাক্টের মিশ্রণ করি । যখন কোনও বিদ্যমান ফাংশন বা পদ্ধতিতে কেবলমাত্র আমার কলটি প্রয়োজন হয় ( for_each( v.begin(), v.end(), boost::bind( &Type::update, _1 ) )) আমি সেই for_eachকনস্ট্রাক্টের জন্য যাই যা কোড থেকে প্রচুর পরিমাণে বয়লার প্লেট পুনরাবৃত্তকারী স্টাফ নেয়। যখন আমার আরও জটিল কিছু প্রয়োজন হয় এবং আমি কোনও ফান্টরকে বাস্তব ব্যবহারের উপরে মাত্র কয়েক লাইন প্রয়োগ করতে পারি না, তখন আমি আমার নিজের লুপটি রোল করি (অপারেশনটি স্থানে রাখে)। কোডের অ-সমালোচনামূলক বিভাগগুলিতে আমি হয়ত BOOST_FOREach এর সাথে যেতে পারি (একজন সহকর্মী আমাকে এতে প্রবেশ করেছিলেন)
পঠনযোগ্যতা এবং কর্মক্ষমতা ছাড়াও, একটি দিক যা সাধারণত উপেক্ষা করা হয় তা হ'ল ধারাবাহিকতা। পুনরুক্তিকারীদের উপর (বা যখন) লুপটি প্রয়োগ করার অনেকগুলি উপায় রয়েছে, এ থেকে:
for (C::iterator iter = c.begin(); iter != c.end(); iter++) {
do_something(*iter);
}
প্রতি:
C::iterator iter = c.begin();
C::iterator end = c.end();
while (iter != end) {
do_something(*iter);
++iter;
}
দক্ষতা এবং বাগ সম্ভাবনার বিভিন্ন স্তরের মধ্যে অনেক উদাহরণ সহ।
For_each ব্যবহার করে তবে লুপটি বাদ দিয়ে ধারাবাহিকতা প্রয়োগ করে:
for_each(c.begin(), c.end(), do_something);
আপনাকে এখনই উদ্বেগের বিষয়টি হ'ল: আপনি বুস্ট বা সি ++ 0 এক্স বৈশিষ্ট্যগুলি ব্যবহার করে লুপ বডিটি ফাংশন, ফান্টেক্টর বা ল্যাম্বডা হিসাবে বাস্তবায়ন করেন? ব্যক্তিগতভাবে, আমি / লুপের জন্য কখন এলোমেলোভাবে প্রয়োগ করতে বা পড়তে হয় তার চেয়ে আমি তার চেয়ে বেশি উদ্বেগ জানাই।
আমি অপছন্দ std::for_eachকরতাম এবং ভেবেছিলাম যে ল্যাম্বদা ছাড়া এটি সম্পূর্ণ ভুলভাবে করা হয়েছিল। তবে আমি কিছুক্ষণ আগে আমার মন পরিবর্তন করেছি এবং এখন আমি আসলে এটি পছন্দ করি। এবং আমি মনে করি এটি এমনকি পাঠযোগ্যতার উন্নতি করে এবং আপনার কোডটিকে টিডিডি উপায়ে পরীক্ষা করা আরও সহজ করে তোলে।
std::for_eachঅ্যালগরিদম যেমন পড়া যায় সীমার মধ্যে সব উপাদান দিয়ে কি কিছু , যা করতে পারেন পাঠযোগ্যতা উন্নতি। বলুন আপনি যে ক্রিয়াটি সম্পাদন করতে চান তা 20 লাইন দীর্ঘ এবং ক্রিয়াটি যেখানে করা হয় তা প্রায় 20 লাইন দীর্ঘ। এটি একটি ফাংশন 40 লাইন দীর্ঘ লুপের জন্য একটি প্রচলিত সাথে তৈরি করবে এবং কেবল প্রায় 20 টি দিয়ে std::for_each, সম্ভবত এটি বোঝা সহজ।
এর জন্য স্ট্যাক্টরগুলি std::for_eachআরও জেনেরিক হওয়ার সম্ভাবনা বেশি এবং তাই পুনরায় ব্যবহারযোগ্য, যেমন:
struct DeleteElement
{
template <typename T>
void operator()(const T *ptr)
{
delete ptr;
}
};
এবং কোডটিতে আপনার কাছে কেবল একটি ওয়ান-লাইনার থাকতে হবে std::for_each(v.begin(), v.end(), DeleteElement())যা একটি স্পষ্ট লুপের চেয়ে আইএমও থেকে কিছুটা ভাল।
লম্বা ফাংশনের মাঝখানে লুপের জন্য স্পষ্টতার চেয়ে ইউনিট টেস্টের অধীনে ct সমস্ত ফান্টেক্টর সাধারণত স্বাভাবিকভাবেই সহজ এবং এটিই আমার পক্ষে ইতিমধ্যে একটি বড় জয়।
std::for_each সাধারণত আরও নির্ভরযোগ্য, কারণ আপনার পরিসীমা নিয়ে কোনও ভুল হওয়ার সম্ভাবনা কম।
এবং সবশেষে, std::for_eachসংকলকটি লুপের জন্য নির্দিষ্ট ধরণের হস্তশিল্পের চেয়ে কিছুটা আরও ভাল কোড তৈরি করতে পারে কারণ এটি (for_each) সবসময় সংকলকটির জন্য একরকম লাগে এবং সংকলক লেখকরা তাদের সমস্ত জ্ঞান রাখতে পারেন, এটি তাদের মতো সুন্দর করে তুলতে করতে পারা.
একই মত অন্যান্য এসটিডি আলগোরিদিম ক্ষেত্রে প্রযোজ্য find_if, transformইত্যাদি
forলুপের জন্য যা প্রতিটি উপাদান বা প্রতিটি তৃতীয় পুনরুক্ত করতে পারে ইত্যাদি for_eachকেবল প্রতিটি উপাদানকে পুনরাবৃত্তি করার জন্য। এটি এর নাম থেকে পরিষ্কার। সুতরাং আপনি আপনার কোডটিতে কী করতে চান তা আরও পরিষ্কার।
++। অস্বাভাবিক হতে পারে, তবে এটি একইভাবে করা লুপ।
transformসেক্ষেত্রে কাউকে বিভ্রান্ত না করার জন্য ব্যবহার করা ভাল ।
আপনি যদি এসটিএল থেকে ঘন ঘন অন্যান্য অ্যালগরিদম ব্যবহার করেন তবে এর বিভিন্ন সুবিধা রয়েছে for_each:
লুপের জন্য একটি traditionalতিহ্যবাহী থেকে পৃথক, for_eachআপনাকে কোড লিখতে বাধ্য করে যা কোনও ইনপুট পুনরাবৃত্তির জন্য কাজ করবে। এইভাবে সীমাবদ্ধ থাকা আসলে একটি ভাল জিনিস হতে পারে কারণ:
for_each।for_eachকখনও কখনও ব্যবহার এটি আরও স্পষ্ট করে তোলে যে আপনি একই জিনিসটি করতে আরও একটি নির্দিষ্ট এসটিএল ফাংশন ব্যবহার করতে পারেন। (জেরি কফিনের উদাহরণের মতো; এটি for_eachঅবশ্যই সবচেয়ে ভাল বিকল্প নয়, তবে লুপের জন্য বিকল্পটি একমাত্র বিকল্প নয়))
সি ++ 11 এবং দুটি সহজ টেম্পলেট সহ আপনি লিখতে পারেন
for ( auto x: range(v1+4,v1+6) ) {
x*=2;
cout<< x <<' ';
}
for_eachএকটি লুপ বা প্রতিস্থাপন হিসাবে কেন এটি ব্রিভিটি এবং সুরক্ষায় উত্সাহিত হয় তা চয়ন করুন, এমন কোনও অভিব্যক্তিতে ত্রুটির সম্ভাবনা নেই।
for_eachলুপ বডি ইতিমধ্যে একটি ফান্টেক্টর যখন ছিল তখন আমার জন্য একই ভিত্তিতে সর্বদা ভাল ছিল এবং আমি যে কোনও সুবিধা পেতে পারি take
আপনি এখনও ত্রি-এক্সপ্রেশন ব্যবহার করেন forতবে এখন যখন আপনি একটি দেখতে পান তখন বুঝতে হবে সেখানে বোঝার মতো কিছু আছে, এটি বয়লারপ্লেট নয়। আমি বয়লারপ্লেটকে ঘৃণা করি । আমি এর অস্তিত্ব বিরক্ত করি। এটি আসল কোড নয়, এটি পড়ে শিখার কিছুই নেই, এটি কেবল আরও একটি বিষয় যাচাই করা দরকার। মানসিক প্রয়াসটি পরিমাপ করা যায় এটি পরীক্ষা করে মরিচা হওয়া কতটা সহজ।
টেম্পলেটগুলি হয়
template<typename iter>
struct range_ {
iter begin() {return __beg;} iter end(){return __end;}
range_(iter const&beg,iter const&end) : __beg(beg),__end(end) {}
iter __beg, __end;
};
template<typename iter>
range_<iter> range(iter const &begin, iter const &end)
{ return range_<iter>(begin,end); }
বেশিরভাগ ক্ষেত্রে আপনাকে পুরো সংগ্রহে পুনরাবৃত্তি করতে হবে । সুতরাং আমি আপনাকে নিজের জন্য_আচ () বৈকল্পিক লিখতে পরামর্শ দিচ্ছি, কেবলমাত্র 2 টি প্যারামিটার নিয়ে। এটি আপনাকে টেরি মাহাফির উদাহরণটিকে আবার লিখতে অনুমতি দেবে :
for_each(container, [](int& i) {
i += 10;
});
আমি মনে করি এটি লুপের চেয়ে সত্যই বেশি পঠনযোগ্য। তবে এর জন্য C ++ 0x সংকলক এক্সটেনশান প্রয়োজন।
আমি পাঠ্যতার পক্ষে খারাপ হতে দেখছি। ধারণাটি একটি ভাল তবে সি ++ কমপক্ষে আমার পক্ষে পঠনযোগ্য লিখতে খুব শক্ত করে তোলে। c ++ 0x লামদা এক্সপ্রেশন সাহায্য করবে। আমি লামদাসের ধারণাটি সত্যিই পছন্দ করি। তবে প্রথম নজরে আমি মনে করি সিনট্যাক্সটি খুব কুৎসিত এবং আমি 100% নিশ্চিত নই যে আমি এর সাথে অভ্যস্ত হয়ে যাব। সম্ভবত 5 বছরে আমি এটিতে অভ্যস্ত হয়ে গিয়েছি এবং এটি দ্বিতীয় চিন্তাও দেব না, তবে সম্ভবত না। সময় বলে দেবে :)
আমি ব্যবহার করতে পছন্দ করি
vector<thing>::iterator istart = container.begin();
vector<thing>::iterator iend = container.end();
for(vector<thing>::iterator i = istart; i != iend; ++i) {
// Do stuff
}
আমি শুরু এবং শেষ পুনরাবৃত্তকারীগুলির জন্য নামযুক্ত ভেরিয়েবলগুলি ব্যবহার করে লুপ ক্লিয়ারারটি পড়ার এবং স্পষ্টতার জন্য স্পষ্ট দেখতে পাই লুপের জন্য বিশৃঙ্খলা হ্রাস করে।
অবশ্যই কেসগুলি পৃথক হয়, এটি আমি সাধারণত সবচেয়ে ভাল পাই।
লুপের মাধ্যমে প্রতিটি পুনরাবৃত্তিতে সঞ্চালিত কোনও ফাংশনে আপনি ইটারেটরকে কল করতে পারেন।
এখানে দেখুন: http://www.cplusplus.com/references/algorithm/for_each/
for_eachকরে যাচ্ছিলেন , কোন ক্ষেত্রে এটি এর সুবিধা সম্পর্কে প্রশ্নের উত্তর দেয় না।
লুপ ভাঙ্গতে পারে জন্য; আমি হার্ব সটারের জন্য তোতা হয়ে উঠতে চাই না তাই তার উপস্থাপনাটির লিঙ্কটি এখানে: http://channel9.msdn.com/Events/BUILD/BUILD2011/TOOL-835T মন্তব্যগুলি অবশ্যই পড়তে ভুলবেন না :)
for_eachআমাদের কাঁটাচামড়ার প্যাটার্ন প্রয়োগ করতে অনুমতি দিন । তা ছাড়া এটি সাবলীল ইন্টারফেস সমর্থন করে ।
gpu::for_eachএকাধিক কর্মীর মধ্যে ল্যাম্বডা টাস্ক কল করে আমরা বিজাতীয়-সমান্তরাল কম্পিউটিংয়ের জন্য চুদা / জিপিইউ ব্যবহার করতে প্রয়োগ যুক্ত করতে পারি ।
gpu::for_each(users.begin(),users.end(),update_summary);
// all summary is complete now
// go access the user-summary here.
এবং gpu::for_each পরবর্তী বিবৃতি কার্যকর করার আগে সমস্ত ল্যাম্বডা-কার্য সমাপ্ত করার জন্য শ্রমিকরা অপেক্ষা করতে পারে।
এটি আমাদের সংক্ষিপ্ত পদ্ধতিতে পাঠযোগ্য কোডটি লেখার অনুমতি দেয়।
accounts::erase(std::remove_if(accounts.begin(),accounts.end(),used_this_year));
std::for_each(accounts.begin(),accounts.end(),mark_dormant);
std::for_eachযখন ব্যবহার করা হয়boost.lambdaবাboost.bindপ্রায়শই পঠনযোগ্যতা উন্নত করতে পারে