সমস্ত <algorithm> ফাংশন কেন কেবল পাত্রে নয়, রেঞ্জ নেয়?


49

এতে অনেক দরকারী ফাংশন রয়েছে <algorithm>তবে এগুলি সমস্তই "সিকোয়েন্স" - জোড়ায় পুনরুক্তিগুলির কাজ করে। উদাহরণস্বরূপ, যদি আমার কাছে একটি ধারক থাকে এবং std::accumulateএটি চালানো পছন্দ করে তবে আমার লিখতে হবে:

std::vector<int> myContainer = ...;
int sum = std::accumulate(myContainer.begin(), myContainer.end(), 0);

যখন আমি যা করতে চাই তা হ'ল:

int sum = std::accumulate(myContainer, 0);

যা কিছুটা বেশি পঠনযোগ্য এবং পরিষ্কার, আমার চোখে।

এখন আমি দেখতে পাচ্ছি যে এমন কিছু ঘটনাও ঘটতে পারে যেখানে আপনি কেবল একটি ধারক অংশে চালিত করতে চান, তাই রেঞ্জগুলি পাশ করার বিকল্পটি পাওয়া অবশ্যই কার্যকর useful তবে কমপক্ষে আমার অভিজ্ঞতায় এটি একটি বিরল বিশেষ ঘটনা। আমি সাধারণত পুরো পাত্রে অপারেট করতে চাই।

এটি একটি র‌্যাপার ফাংশন লিখতে সহজ যা একটি ধারক গ্রহণ করে এবং কল করে begin()এবং end()এটিতে, তবে এই জাতীয় সুবিধাগুলি স্ট্যান্ডার্ড লাইব্রেরিতে অন্তর্ভুক্ত নয়।

আমি এই এসটিএল ডিজাইনের পছন্দের পিছনে যুক্তি জানতে চাই।


7
এসটিএল সাধারণত সুবিধাজনক মোড়ক সরবরাহ করে, বা এটি পুরানো সি ++ অনুসরণ করে এখানে-এখন-সরঞ্জাম-এখন-গো-নিজেই নিজেকে-পাদদেশ নীতিতে অনুসরণ করে?
কিলিয়ান ফট 13

2
রেকর্ডের জন্য: নিজের র‍্যাপারটি লেখার পরিবর্তে আপনার বুস্ট.রেঞ্জে আলগোরিদিম র‌্যাপার ব্যবহার করা উচিত; এই ক্ষেত্রে,boost::accumulate
ইকামত্মর

উত্তর:


40

... রেঞ্জগুলি অতিক্রম করার বিকল্পটি পাওয়া এটি অবশ্যই কার্যকর। তবে কমপক্ষে আমার অভিজ্ঞতায় এটি একটি বিরল বিশেষ ঘটনা। আমি সাধারণত পুরো পাত্রে অপারেট করতে চাই

এটি আপনার অভিজ্ঞতার মধ্যে একটি বিরল বিশেষ কেস হতে পারে তবে বাস্তবে পুরো ধারকটিই বিশেষ ক্ষেত্রে এবং স্বেচ্ছাসেবী পরিসীমাটি সাধারণ ক্ষেত্রে।

আপনি ইতিমধ্যে লক্ষ্য করেছেন যে আপনি বর্তমান ইন্টারফেসটি ব্যবহার করে পুরো কন্টেইনার কেসটি বাস্তবায়ন করতে পারেন , তবে আপনি কনভার্সটি করতে পারবেন না।

সুতরাং, গ্রন্থাগার-লেখকের সামনে দুটি ইন্টারফেস প্রয়োগ করার মধ্যে বা কেবল একটি বাস্তবায়ন যা এখনও সমস্ত ক্ষেত্রে আচ্ছাদন করে তার মধ্যে একটি পছন্দ ছিল।


একটি র‌্যাপার ফাংশন লিখতে সহজ যা একটি ধারক গ্রহণ করে এবং এটিতে কল শুরু () এবং শেষ () হয়, তবে এই জাতীয় সুবিধার ফাংশনগুলি স্ট্যান্ডার্ড লাইব্রেরিতে অন্তর্ভুক্ত নয়

সত্য, বিশেষত যেহেতু বিনামূল্যে ফাংশন std::beginএবং std::endএখন অন্তর্ভুক্ত রয়েছে।

সুতরাং, আসুন আমরা লাইব্রেরিটি সুবিধার ওভারলোড সরবরাহ করে:

template <typename Container>
void sort(Container &c) {
  sort(begin(c), end(c));
}

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

তবে আমরা কমপক্ষে প্রতিটি ক্ষেত্রেই আচ্ছাদিত করেছি যেখানে আমরা একটি সম্পূর্ণ ধারকটিতে কাজ করতে চাই, তাই না? ভাল, বেশ না। বিবেচনা

std::for_each(c.rbegin(), c.rend(), foo);

আমরা অপারেটিং হ্যান্ডেল করতে চান, পিছন পাত্রে উপর, আমরা প্রয়োজন অন্য বিদ্যমান অ্যালগরিদম প্রতি পদ্ধতি (অথবা পদ্ধতি এর একটি জোড়া)।


সুতরাং, পরিসীমা ভিত্তিক পদ্ধতির সাধারণ অর্থে আরও সাধারণ যে:

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

এর আর একটি বৈধ কারণ রয়েছে, এটি হ'ল এটি যে এসটিএলকে মানসম্পন্ন করার জন্য ইতিমধ্যে প্রচুর কাজ ছিল এবং এটি ব্যাপকভাবে ব্যবহৃত হওয়ার আগে এটি সুবিধাযুক্ত মোড়ক দিয়ে স্ফীত করা সীমিত কমিটির সময়ের দুর্দান্ত ব্যবহার হবে না। আপনি যদি আগ্রহী হন তবে আপনি এখানে স্টেপানভ এবং লির প্রযুক্তিগত প্রতিবেদনটি খুঁজে পেতে পারেন

মন্তব্যে উল্লিখিত হিসাবে, বুস্ট.রেঞ্জ স্ট্যান্ডার্ডে পরিবর্তনের প্রয়োজন ছাড়াই একটি নতুন পদ্ধতির সরবরাহ করে।


9
আমি মনে করি না যে, ওপি অন্তর্ভুক্ত, কেউ প্রতিটি বিশেষ ক্ষেত্রে ওভারলোডগুলি যুক্ত করার পরামর্শ দিচ্ছে। এমনকি "পুরো পাত্রে" "একটি স্বেচ্ছাচারী পরিসীমা" এর চেয়ে কম সাধারণ থাকলেও এটি অবশ্যই "সম্পূর্ণ ধারক, বিপরীত" এর চেয়ে অনেক বেশি সাধারণ। এটিকে সীমাবদ্ধ করুন f(c.begin(), c.end(), ...)এবং সম্ভবত ওভারলোডের সংখ্যা দ্বিগুণ হওয়া রোধ করতে কেবল সর্বাধিক ব্যবহৃত ওভারলোড (তবে আপনি এটি নির্ধারণ করেন)। এছাড়াও, আইটিরেটর অ্যাডাপ্টারগুলি সম্পূর্ণ অর্থেগোনাল (যেমন আপনি লক্ষ্য করেছেন যে তারা পাইথনগুলিতে সূক্ষ্মভাবে কাজ করে, যার পুনরাবৃত্তিগুলি খুব আলাদাভাবে কাজ করে এবং আপনি যে শক্তি সম্পর্কে কথা বলেন তার বেশিরভাগ শক্তি নেই)।

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

23
নোট করুন কনটেইনার সংস্করণটি সমস্ত ক্ষেত্রে কভার করবে যদি এসটিএল একটি পরিসীমা বস্তু সরবরাহ করে; যেমন std::sort(std::range(start, stop))

3
বিপরীতে: কম্পোজেবল ফাংশনাল অ্যালগরিদম (যেমন মানচিত্র এবং ফিল্টার) কোনও একক বস্তু গ্রহণ করে যা কোনও সংগ্রহকে উপস্থাপন করে এবং একটি একক বস্তু ফেরত দেয়, তারা অবশ্যই পুনরুক্তি জুটির অনুরূপ কিছু ব্যবহার করে না।
সুইভ

3
একটি ম্যাক্রো এটি করতে পারে: #define MAKE_RANGE(container) (container).begin(), (container).end()</ jj>
রাচেট ফ্রিক

21

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

template<typename Iter>
void sort( Iter, Iter ); // 1

template<typename Iter, typename Pred>
void sort( Iter, Iter, Pred ); // 2

এবং নিম্নলিখিতগুলি যুক্ত করুন:

template<typename Container>
void sort( Container& ); // 3

template<typename Container, typename Pred>
void sort( Container&, Pred ); // 4

এটি আলাদা 4এবং 1সঠিকভাবে আলাদা করা শক্ত করে তুলবে ।

প্রস্তাবিত হিসাবে ধারণাগুলি, তবে শেষ পর্যন্ত সি ++ 0x এর অন্তর্ভুক্ত নয়, এটি সমাধান করতে পারত এবং এটি ব্যবহার করে এটিকে অবরুদ্ধ করাও সম্ভব enable_if। কিছু অ্যালগরিদমের জন্য এটি কোনও সমস্যা নয়। তবে তারা এর বিরুদ্ধে সিদ্ধান্ত নিয়েছে।

এখন এখানে সমস্ত মন্তব্য এবং উত্তর পড়ার পরে, আমি মনে করি rangeঅবজেক্টগুলি সর্বোত্তম সমাধান হবে। আমি মনে করি আমি একবার তাকান Boost.Range


1
ঠিক আছে, কেবলমাত্র একটি ব্যবহার typename Iterকরা কঠোর ভাষার জন্য খুব হাঁস-টাইপযুক্ত বলে মনে হচ্ছে। আমি যেমন পছন্দ করেন template<typename Container> void sort(typename Container::iterator, typename Container::iterator); // 1এবং template<template<class> Container, typename T> void sort( Container<T>&, std::function<bool(const T&)> ); // 4ইত্যাদি (যা সম্ভবত অস্পষ্টতা সমস্যা সমাধানের হবে)
Vlad

@ ভ্লাদ: দুর্ভাগ্যক্রমে, এটি সহজ পুরানো অ্যারেগুলির জন্য কাজ করবে না, কারণ সেখানে কোনও T[]::iteratorউপলভ্য নেই। এছাড়াও, যথাযথ পুনরাবৃত্তিকারী কোনও সংগ্রহের নেস্টেড ধরণের হতে বাধ্য নয়, এটি সংজ্ঞায়িত করার পক্ষে যথেষ্ট std::iterator_traits
ফায়ারগুরাফিকু

@ ফায়ারগুরাফিকু: ঠিক আছে, কিছু প্রাথমিক টিএমপি ট্রিকস দ্বারা অ্যারেগুলি বিশেষ ক্ষেত্রে সহজ।
ভ্লাদ 18

11

মূলত উত্তরাধিকারের সিদ্ধান্ত পুনরুক্তি ধারণা পয়েন্টারে মডেল করা হয়, তবে ধারকগুলি অ্যারেগুলিতে মডেল করা হয় না। তদতিরিক্ত, যেহেতু অ্যারেগুলি পাস করা শক্ত হয় (সাধারণত দৈর্ঘ্যের জন্য একটি নন-টাইপ টেম্পলেট প্যারামিটার প্রয়োজন), প্রায়শই একটি ফাংশনে কেবল পয়েন্টার পাওয়া যায়।

তবে হ্যাঁ, দূরবর্তী দৃষ্টিতে সিদ্ধান্তটি ভুল। আমরা উভয় থেকে begin/endবা গঠনমূলক একটি পরিসীমা অবজেক্টের সাথে আরও ভাল হত begin/length; _nপরিবর্তে এখন আমাদের একাধিক প্রত্যয়যুক্ত অ্যালগরিদম রয়েছে।


5

এগুলি যুক্ত করা আপনার কোনও শক্তি অর্জন করতে পারে না (আপনি ইতিমধ্যে কল করে .begin()এবং .end()নিজের মাধ্যমে পুরো পাত্রে এটি করতে পারেন), এবং এটি লাইব্রেরিতে আরও একটি জিনিস যুক্ত করবে যা সঠিকভাবে নির্দিষ্ট করতে হবে, বিক্রেতাদের দ্বারা লাইব্রেরিতে যুক্ত করা, পরীক্ষা করা, রক্ষণাবেক্ষণ, ইত্যাদি, ইত্যাদি

সংক্ষেপে, এটি সম্ভবত সেখানে নেই কারণ কেবলমাত্র অতিরিক্ত ধারক ব্যবহারকারীদের একটি অতিরিক্ত ফাংশন কল প্যারামিটার টাইপ করা থেকে বাঁচাতে অতিরিক্ত টেম্পলেটগুলির সেট বজায় রাখা কোনও সমস্যা নয়।


9
এটি আমার শক্তি অর্জন করতে পারে না, এটি সত্য - তবে শেষ পর্যন্ত, না হয় std::getline, এবং এখনও, এটি লাইব্রেরিতে রয়েছে। যে কেউ এতদূর যেতে পারে যে বর্ধিত নিয়ন্ত্রণ কাঠামো আমার শক্তি অর্জন করে না, কারণ আমি কেবল ifএবং goto। হ্যাঁ, অন্যায্য তুলনা, আমি জানি;) আমি মনে করি যে আমি কোনওভাবে স্পেসিফিকেশন / বাস্তবায়ন / রক্ষণাবেক্ষণের বোঝা বুঝতে পারি তবে এটি কেবলমাত্র একটি ছোট্ট র‍্যাপার যা আমরা এখানে বলছি, তাই ..
প্রাণঘাতী-গিটার

একটি ক্ষুদ্র মোড়কের কোড কোডের জন্য কিছুই হয় না এবং এটি লাইব্রেরিতে থাকার কোনও মানে হয় না।
ebasconp

-1

এখন অবধি , http://en.wikedia.org/wiki/C++11#Range-based_for_loop এর জন্য একটি দুর্দান্ত বিকল্প std::for_each। সুস্পষ্ট পুনরাবৃত্তকারী পর্যবেক্ষণ করুন:

int a[5] = {1, 2, 3, 4, 5};
for (auto &i: a) { i *= 2; }

( Https://stackoverflow.com/a/694534/2097284 দ্বারা অনুপ্রাণিত ।)


1
এটি কেবলমাত্র সেই একক অংশের জন্যই সমাধান করে <algorithm>, সমস্ত আসল আলগোগুলি যা প্রয়োজন beginএবং পুনরাবৃত্তিকারীদের endনয় - তবে সুবিধাটি বাড়িয়ে দেওয়া যায় না! আমি যখন ২০০৯ সালে প্রথম C ++ 03 চেষ্টা করেছিলাম তখন লুপিংয়ের বয়লারপ্লেটের কারণে আমি পুনরাবৃত্তিকারীদের কাছ থেকে দূরে সরে গিয়েছিলাম এবং ভাগ্যক্রমে বা না, আমার প্রকল্পগুলি তখন অনুমোদিত হয়েছিল। 2014 সালে সি ++ 11 এ পুনরায় চালু করা, এটি একটি অবিশ্বাস্য আপগ্রেড ছিল, ভাষা সি ++ সবসময়ই হওয়া উচিত ছিল এবং এখন আমি ছাড়া বাঁচতে পারি না auto &it: them:)
আন্ডারস্কোর_১১
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.