C ++ 20 में कार्यान्वित किए जाने का इरादा शिफ्ट_ राइट () कैसे है?


9

C ++ 20 में, <algorithm>हेडर दो नए एल्गोरिदम प्राप्त करता है: shift_left()औरshift_right() । दोनों किसी भी LegacyForwardIterator को स्वीकार करते हैं। के लिए shift_left(), यह निर्दिष्ट किया जाता है कि "चालें iशुरू से बढ़ते क्रम में की जाती हैं ​0"; के लिए shift_right(), यह निर्दिष्ट किया जाता है कि "यदि ForwardItLegacyBidirectionalIterator आवश्यकताओं को पूरा करता है, तो चालें 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);
}

यदि ForwardItLegacyBidirectionalIterator आवश्यकताओं को पूरा करता है, तो मैं देख सकता हूं कि 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...
एकॉनकागुआ

@Aconcagua ओह, हाँ, मैं इस प्रश्न का संपादन करूँगा।
बर्नार्ड

जवाबों:


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

@YSC के खिलाफ सुरक्षा की रक्षा "घातक परिणाम" चेतावनियों
Caleth

@vll मैंने जो सोचा था।
YSC

5
@ वाईएससी शायद अतिभारित अल्पविराम संचालकों से रक्षा करे, जिन्हें बुलाया नहीं जाना चाहिए।
अखरोट

@ मेवात हो तुम सही हो सकता है!
YSC
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.