শিফট_রাইট () কীভাবে সি ++ ২০ এ প্রয়োগ করা হবে?


9

সি ++ ২০ এ, <algorithm>শিরোনামটি দুটি নতুন অ্যালগরিদম অর্জন করেছে: shift_left()এবংshift_right() । উভয়েই কোনও লিগ্যাসি ফরওয়ার্ডআইট্রেটর গ্রহণ করে। কারণ shift_left(), এটি নির্দিষ্ট করা আছে যে "চালগুলি iশুরু থেকে ক্রমবর্ধমান ক্রমে সঞ্চালিত হয় ​0"; কারণ shift_right(), এটি নির্দিষ্ট করা আছে যে "যদি ForwardItলিগ্যাসিবিডায়ারেশনালআইটরেটরের প্রয়োজনীয়তা পূরণ হয় তবে চালগুলি " iথেকে শুরু করার ক্রমহ্রাসমান ক্রমে সঞ্চালিত হয় last - first - n - 1"।

আমি কার্যকর করার পক্ষে যুক্তিসঙ্গত সহজ উপায় সম্পর্কে ভাবতে পারি shift_left():

template <typename ForwardIt>
constexpr inline ForwardIt shift_left(ForwardIt first, ForwardIt last, typename std::iterator_traits<ForwardIt>::difference_type n) {
    if (n <= 0) return last;
    ForwardIt it = first;
    for (; n > 0; --n, ++it) {
        if (it == last) return first;
    }
    return std::move(it, last, first);
}

যদি ForwardItলিগ্যাসিবিডায়ারেশনালআইট্রেটারের প্রয়োজনীয়তাগুলি পূরণ করে তবে আমি দেখতে পাচ্ছি যে shift_right()এটি খুব একইভাবে প্রয়োগ করা যেতে পারে shift_left()। যাইহোক, এটি shift_right()কোনও ক্ষেত্রে বাই-ডাইরেক্টরিয়াল ফরোয়ার্ড ইটারেটরগুলির জন্য কীভাবে প্রয়োগ করতে পারে তা মোটেও পরিষ্কার নয় ।

আমি একটি অ্যালগরিদম বের করেছি যা [first, first+n)উপাদানগুলির অদলবদলের জন্য স্ক্র্যাচ স্পেস হিসাবে স্থানটি ব্যবহার করে, তবে এটি shift_left()উপরের অ্যালগরিদমের চেয়ে কিছুটা অপব্যয়যুক্ত বলে মনে হচ্ছে :

template <typename ForwardIt>
constexpr inline ForwardIt shift_right(ForwardIt first, ForwardIt last, typename std::iterator_traits<ForwardIt>::difference_type n) {
    if (n <= 0) return first;
    ForwardIt it = first;
    for (; n > 0; --n, ++it) {
        if (it == last) return last;
    }
    ForwardIt ret = it;
    ForwardIt ret_it = first;
    for (; it != last; ++it) {
        std::iter_swap(ret_it, it);
        ret_it++;
        if (ret_it == ret) ret_it = first;
    }
    return ret;
}

বাস্তবায়নের shift_right()কি আরও ভাল বা "উদ্দেশ্যপ্রণোদিত" উপায় থাকবে ?


এর std::moveপরিবর্তে বাস্তবায়নটি ব্যবহার করা হবে std::copy...
অ্যাকনকাগুয়া

@ আঙ্কাকাগুয়া উফ, হ্যাঁ, আমি প্রশ্নটি সম্পাদনা করব।
বার্নার্ড

উত্তর:


6

শিফটগুলির জন্য এটি নমুনা বাস্তবায়ন: https://github.com/danra/shift_proposal/blob/master/shift_proposal.h

প্রস্তাবের নথি থেকে: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0769r0.pdf

#include <algorithm>
#include <iterator>
#include <type_traits>
#include <utility>

template<class I>
using difference_type_t = typename std::iterator_traits<I>::difference_type;

template<class I>
using iterator_category_t = typename std::iterator_traits<I>::iterator_category;

template<class I, class Tag, class = void>
constexpr bool is_category = false;
template<class I, class Tag>
constexpr bool is_category<I, Tag, std::enable_if_t<
    std::is_convertible_v<iterator_category_t<I>, Tag>>> = true;

/// Increment (decrement for negative n) i |n| times or until i == bound,
/// whichever comes first. Returns n - the difference between i's final position
/// and its initial position. (Note: "advance" has overloads with this behavior
/// in the Ranges TS.)
template<class I>
constexpr difference_type_t<I> bounded_advance(
    I& i, difference_type_t<I> n, I const bound)
{
    if constexpr (is_category<I, std::bidirectional_iterator_tag>) {
        for (; n < 0 && i != bound; ++n, void(--i)) {
            ;
        }
    }

    for(; n > 0 && i != bound; --n, void(++i)) {
        ;
    }

    return n;
}

template<class ForwardIt>
ForwardIt shift_left(ForwardIt first, ForwardIt last, difference_type_t<ForwardIt> n)
{
    if (n <= 0) {
        return last;
    }

    auto mid = first;
    if (::bounded_advance(mid, n, last)) {
        return first;
    }

    return std::move(std::move(mid), std::move(last), std::move(first));
}

template<class ForwardIt>
ForwardIt shift_right(ForwardIt first, ForwardIt last, difference_type_t<ForwardIt> n)
{
    if (n <= 0) {
        return first;
    }

    if constexpr (is_category<ForwardIt, std::bidirectional_iterator_tag>) {
        auto mid = last;
        if (::bounded_advance(mid, -n, first)) {
            return last;
        }
        return std::move_backward(std::move(first), std::move(mid), std::move(last));
    } else {
        auto result = first;
        if (::bounded_advance(result, n, last)) {
            return last;
        }

        // Invariant: next(first, n) == result
        // Invariant: next(trail, n) == lead

        auto lead = result;
        auto trail = first;

        for (; trail != result; ++lead, void(++trail)) {
            if (lead == last) {
                // The range looks like:
                //
                //   |-- (n - k) elements --|-- k elements --|-- (n - k) elements --|
                //   ^-first          trail-^                ^-result          last-^
                //
                // Note that distance(first, trail) == distance(result, last)
                std::move(std::move(first), std::move(trail), std::move(result));
                return result;
            }
        }

        for (;;) {
            for (auto mid = first; mid != result; ++lead, void(++trail), ++mid) {
                if (lead == last) {
                    // The range looks like:
                    //
                    //   |-- (n - k) elements --|-- k elements --|-- ... --|-- n elements --|
                    //   ^-first            mid-^         result-^         ^-trail     last-^
                    //
                    trail = std::move(mid, result, std::move(trail));
                    std::move(std::move(first), std::move(mid), std::move(trail));
                    return result;
                }
                std::iter_swap(mid, trail);
            }
        }
    }
}

3
আমি অবাক হই কেন void(++trail)...
ওয়াইএসসি

@YSC অতিমাত্রায় "বাতিল হওয়া ফলাফল" সতর্কবার্তা থেকে রক্ষা করছে
কালেথ

@vll এটাই আমি ভেবেছিলাম
ওয়াইএসসি

5
@ ওয়াইএসসি সম্ভবত অতিরিক্ত লোড কমা অপারেটরদের থেকে রক্ষা করার জন্য যাদের ডাকা হয় না বলে মনে করা হয়।
আখরোট

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