Std :: std :: back_inserter দিয়ে রূপান্তর করা বৈধ?


20

Cppreferences এর জন্য এই উদাহরণ কোডটি রয়েছে std::transform:

std::vector<std::size_t> ordinals;
std::transform(s.begin(), s.end(), std::back_inserter(ordinals),
               [](unsigned char c) -> std::size_t { return c; });

তবে এটি আরও বলে:

std::transformunary_opবা এর অর্ডার প্রয়োগের গ্যারান্টি দেয় না binary_op। ক্রমটিকে ক্রমানুসারে ক্রম প্রয়োগ করতে বা ক্রমের উপাদানগুলিকে সংশোধন করে এমন একটি ফাংশন প্রয়োগ করতে, ব্যবহার করুন std::for_each

এটি সম্ভবত সমান্তরাল বাস্তবায়নের অনুমতি দেওয়ার জন্য। তবে তৃতীয় প্যারামিটারটি std::transformহ'ল LegacyOutputIteratorএর জন্য নিম্নলিখিত পোস্টকন্ডিশন রয়েছে ++r:

এই ক্রিয়াকলাপের পরে rইনক্রিমেন্টেবল হওয়ার প্রয়োজন হয় না এবং এর আগের মানটির কোনও অনুলিপি rআর আর ডিফারেন্সযোগ্য বা ইনক্রিমেন্টেবল হয় না।

সুতরাং এটি আমার কাছে মনে হচ্ছে আউটপুট বরাদ্দ অবশ্যই অবশ্যই ঘটবে। এগুলির কি সহজভাবে বোঝায় যে প্রয়োগটি প্রয়োগের unary_opবাইরে চলে যেতে পারে এবং অস্থায়ী স্থানে সঞ্চিত হতে পারে তবে আউটপুটটিকে ক্রমে অনুলিপি করা হয়েছে? এটি এমন কিছু শোনাচ্ছে না যা আপনি কখনও করতে চান ever

বেশিরভাগ সি ++ গ্রন্থাগারগুলি আসলে সমান্তরাল এক্সিকিউটিউটর এখনও বাস্তবায়ন করতে পারেনি, তবে মাইক্রোসফ্ট করেছে। আমি নিশ্চিত এই প্রাসঙ্গিক কোড, এবং আমি মনে করি এটা কল এই populate()ফাংশন আউটপুট, যা নিশ্চয় কারণ করতে একটি বৈধ জিনিস না এর অংশ রেকর্ড iterators করার LegacyOutputIteratorএটা কপি বৃদ্ধিশীল দ্বারা invalidated করা যেতে পারে।

আমি কী মিস করছি?


গডবোল্টের একটি সাধারণ পরীক্ষা দেখায় এটি একটি সমস্যা। সি ++ 20 এবং transformসংস্করণ সহ যা প্যারালাইলিজম ব্যবহার করবেন কি না তা স্থির করে। transformবড় ভেক্টরের জন্য ব্যর্থ।
ক্রোলম্যান

6
@ ক্রোলম্যান আপনার কোডটি ভুল, যেহেতু আপনি ব্যাক সন্নিবেশ করছেন sযা পুনরাবৃত্তিকারীদের অবৈধ করে।
ড্যানিয়েল ল্যাঙ্গার

পুনঃটুইট করেছেন এটি টুইট করে এবং অ-বৈধ অবস্থায় রেখেছিল। আমি আমার মন্তব্য ফিরে।
ক্রোলম্যান

আপনি যদি std::transformনিষেধাজ্ঞার নীতিটি ব্যবহার করেন তবে এলোমেলো অ্যাক্সেসের পুনরুদ্ধারের প্রয়োজন যা back_inserterপূরণ করতে পারে না। আইএমও উদ্ধৃত অংশ ডকুমেন্টেশন সেই দৃশ্যের উল্লেখ করে। নথি ব্যবহারের ক্ষেত্রে নোট উদাহরণ std::back_inserter
মারেক আর

@ ক্রোলম্যান স্বয়ংক্রিয়ভাবে সমান্তরাল ব্যবহার করার সিদ্ধান্ত নিয়েছে?
কৌতূহলী

উত্তর:


9

1) স্ট্যান্ডার্ডে আউটপুট পুনরাবৃত্তির প্রয়োজনীয়তা সম্পূর্ণরূপে ভাঙা। LWG2035 দেখুন ।

2) আপনি যদি খাঁটি আউটপুট পুনরাবৃত্তকারী এবং একটি খাঁটি ইনপুট উত্স পরিসীমা ব্যবহার করেন, তবে অনুশীলনে অ্যালগরিদম আর কিছু করতে পারে না; ক্রমে লিখতে ছাড়া এটির কোনও বিকল্প নেই। (তবে, একটি কাল্পনিক বাস্তবায়ন তার নিজস্ব ধরণের বিশেষ ক্ষেত্রে বেছে নিতে পারে, যেমন std::back_insert_iterator<std::vector<size_t>>; কোনও বাস্তবায়ন কেন এখানে করতে চায় তা আমি দেখতে পাই না, তবে এটি করার অনুমতি দেওয়া হয়েছে is)

3) মানক এমন কোনও গ্যারান্টি নেই যা transformরূপান্তরগুলিকে যাতে করে প্রয়োগ করে। আমরা একটি বাস্তবায়নের বিশদটি খুঁজছি।

এর std::transformজন্য কেবলমাত্র আউটপুট পুনরাবৃত্তির প্রয়োজন এটির অর্থ এই নয় যে এটি উচ্চতর পুনরুক্তিকারী শক্তিগুলি সনাক্ত করতে পারে না এবং এই জাতীয় ক্ষেত্রে অপারেশনগুলি পুনরায় অর্ডার করতে পারে। বস্তুত, আলগোরিদিম পুনরুক্তিকারীর শক্তির উপর প্রাণবধ সব সময় , এবং তারা (পয়েন্টার বা ভেক্টর iterators মত) বিশেষ পুনরুক্তিকারীর ধরনের জন্য বিশেষ হ্যান্ডলিং আছে সব সময়

স্ট্যান্ডার্ডটি যখন কোনও নির্দিষ্ট অর্ডারের গ্যারান্টি দিতে চায়, তখন এটি কীভাবে বলতে হয় তা ( std::copy"এর থেকে শুরু করে firstএগিয়ে যাওয়া last" দেখুন) knows


5

থেকে n4385:

.625.6.4 রূপান্তর :

template<class InputIterator, class OutputIterator, class UnaryOperation>
constexpr OutputIterator
transform(InputIterator first1, InputIterator last1, OutputIterator result, UnaryOperation op);

template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2, class UnaryOperation>
ForwardIterator2
transform(ExecutionPolicy&& exec, ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 result, UnaryOperation op);

template<class InputIterator1, class InputIterator2, class OutputIterator, class BinaryOperation>
constexpr OutputIterator
transform(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, OutputIterator result, BinaryOperation binary_op);

template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2, class ForwardIterator, class BinaryOperation>
ForwardIterator
transform(ExecutionPolicy&& exec, ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator result, BinaryOperation binary_op);

.523.5.2.1.2 back_inserter

template<class Container>
constexpr back_insert_iterator<Container> back_inserter(Container& x);

রিটার্নস: back_insert_iterator (x)

.523.5.2.1 ক্লাস টেম্পলেট back_insert_iterator

using iterator_category = output_iterator_tag;

সুতরাং এর std::back_inserterসমান্তরাল সংস্করণ ব্যবহার করা যাবে না std::transform। আউটপুট পুনরাবৃত্তিকারীদের সমর্থন করে এমন সংস্করণগুলি ইনপুট পুনরাবৃত্তকারীগুলির সাথে তাদের উত্স থেকে পড়ে। যেহেতু ইনপুট পুনরাবৃত্তি কেবল পূর্ব-ও পোস্ট-ইনক্রিমেন্ট (§23.3.5.2 ইনপুট পুনরাবৃত্তকারী) হতে পারে এবং কেবল অনুক্রমিক ( যেমন সমান্তরাল নয়) এক্সিকিউশন থাকে তাই তাদের এবং আউটপুট পুনরাবৃত্তির মধ্যে ক্রম অবশ্যই সংরক্ষণ করা উচিত।


2
নোট করুন যে সি ++ স্ট্যান্ডার্ডের এই সংজ্ঞাগুলি অতিরিক্ত ধরণের পুনরাবৃত্তির জন্য নির্বাচিত অ্যালগরিদমের বিশেষ সংস্করণ সরবরাহ করতে প্রয়োগগুলি এড়ায় না। উদাহরণস্বরূপ, std::advanceকেবলমাত্র একটি সংজ্ঞা রয়েছে যা ইনপুট-পুনরাবৃত্তিকে গ্রহণ করে তবে libstdc ++ দ্বিদ্বি-পুনরুক্তি এবং র্যান্ডম-অ্যাক্সেস-পুনরাবৃত্তির জন্য অতিরিক্ত সংস্করণ সরবরাহ করে । নির্দিষ্ট সংস্করণটি পরে পাস করা পুনরাবৃত্তির ধরণের ভিত্তিতে কার্যকর করা হয়
ড্যানিয়েল ল্যাঙ্গার

আপনার মন্তব্যটি সঠিক বলে আমি মনে করি না - ForwardIteratorএর অর্থ এই নয় যে আপনাকে জিনিসগুলি যথাযথভাবে করতে হবে। তবে আপনি যে জিনিসটি মিস করেছেন তা আপনি হাইলাইট করেছেন - যে সমান্তরাল সংস্করণগুলি তারা ব্যবহার করে ForwardIteratorনা তার জন্য OutputIterator
টিমম্মে

1
আহ ঠিক আছে, হ্যাঁ আমি মনে করি আমরা একমত হচ্ছি।
টিএমএমএম

1
এর উত্তরটি আসলে কী বোঝায় তা বোঝাতে কিছু শব্দ যুক্ত করে উপকৃত হতে পারে।
ব্যারি

1
@ ব্যারি কিছু শব্দ যুক্ত করেছেন, যে কোনও এবং সমস্ত ফিড ফিরে প্রশংসিত।
পল ইভান্স

0

সুতরাং আমি যে জিনিসটি মিস করেছি তা হ'ল সমান্তরাল সংস্করণগুলি গ্রহণ করে LegacyForwardIterator, না LegacyOutputIterator। একজন LegacyForwardIterator পারেন , এটা কপি invalidating ছাড়া বৃদ্ধি করা, তাই এটি এই ব্যবহার করার জন্য একটি আউট-অফ-অর্ডার সমান্তরাল বাস্তবায়ন করা সহজ std::transform

আমি মনে করি এর অ-সমান্তরাল সংস্করণগুলি std::transform অবশ্যই ক্রমে কার্যকর করা উচিত । হয় হয় cppreferences এটি সম্পর্কে ভুল, বা সম্ভবত স্ট্যান্ডার্ড এই প্রয়োজনীয়তা অন্তর্নিহিত কারণ এটি বাস্তবায়নের অন্য কোন উপায় নেই। (শটগান স্ট্যান্ডার্ডের মধ্যে দিয়ে বেড়াচ্ছে না তা জানতে!)


রূপান্তরকরণের অ সমান্তরাল সংস্করণগুলি যদি সমস্ত পুনরাবৃত্তি যথেষ্ট শক্তিশালী হয় তবে আউট-অফ-অর্ডার কার্যকর করতে পারে। প্রশ্নে উদাহরণে তারা নয়, তাই যে বিশেষজ্ঞতা এর transformমধ্যে-অর্ডার হতে হবে।
কালেথ

না তারা নাও পারে, কারণ LegacyOutputIteratorআপনাকে এটিকে ক্রমে ব্যবহার করতে বাধ্য করে।
টিম্ম্ম্ম

এটি std::back_insert_iterator<std::vector<T>>এবং এর জন্য আলাদাভাবে বিশেষজ্ঞ করতে পারে std::vector<T>::iterator। প্রথমটি অবশ্যই ক্রমযুক্ত হতে হবে। দ্বিতীয়টির তেমন কোনও বিধিনিষেধ নেই
কালেথ

আহ অপেক্ষা করুন আমি কী বোঝাতে চাইছি - আপনি যদি LegacyForwardIteratorঅ-সমান্তরালে পাস transformকরতে চান তবে এটির জন্য এটি বিশেষায়িত হতে পারে যা এটি ক্রম ছাড়াই চলে। ভাল যুক্তি.
টিম্ম্ম

0

আমি বিশ্বাস করি যে রূপান্তরটি ক্রমে প্রক্রিয়াভুক্ত হওয়ার নিশ্চয়তা রয়েছে[back.insert.iterator] অনুসারে std::back_inserter_iteratorএকটি আউটপুট পুনরাবৃত্তকারী (এর iterator_categoryসদস্য প্রকারের জন্য একটি উপাধি রয়েছে std::output_iterator_tag) ।

ফলে, std::transformহয়েছে অন্য কোন বিকল্প কিভাবে কল সদস্য চেয়ে পরবর্তী পুনরাবৃত্তিতে এগিয়ে যেতে উপর operator++উপর resultপ্যারামিটার।

অবশ্যই, এটি কার্যকরকরণের নীতি ছাড়াই কেবল ওভারলোডের জন্য বৈধ, যেখানে std::back_inserter_iteratorএটি ব্যবহার করা যেতে পারে না (এটি কোনও ফরোয়ার্ডিং ইটারেটর নয় )।


বিটিডাব্লু, আমি সিপ্রেফারেন্সের উদ্ধৃতি দিয়ে তর্ক করব না। সেখানে বিবৃতি প্রায়শই অনর্থক বা সরলীকৃত হয়। এগুলি হিসাবে ক্ষেত্রে, সি ++ স্ট্যান্ডার্ডটি দেখতে ভাল। যেখানে, সম্পর্কিত std::transform, অপারেশন ক্রম সম্পর্কে কোন উদ্ধৃতি নেই।


"সি ++ স্ট্যান্ডার্ড। কোথায়, স্ট্যান্ড :: ট্রান্সফর্ম সম্পর্কিত বিষয়ে, ক্রমের ক্রম সম্পর্কে কোনও উদ্ধৃতি নেই" যেহেতু আদেশটির উল্লেখ নেই, তাই এটি অনির্দিষ্ট নয়?
হলি ব্ল্যাককিট

@ হোলিব্ল্যাকগ্যাট সুস্পষ্টভাবে অনির্দিষ্ট, তবে আউটপুট পুনরাবৃত্তকারী দ্বারা আরোপিত। নোট করুন আউটপুট পুনরাবৃত্তকারীগুলির সাথে, একবার আপনি এটি বাড়িয়ে দেওয়ার পরে, আপনি কোনও পূর্ববর্তী পুনরাবৃত্তির মানকে অবজ্ঞা নাও করতে পারেন।
ড্যানিয়েল ল্যাঙ্গার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.