#include <iterator>
#include <initializer_list>
#include <vector>

class istack { // stack of ints
    // the template should be written after the range functions
    template <typename ValueType>
    class iter {
        // making the container class a friend is needed so that the container can use the private constructor
        // it's usually best to limit how a class can be constructed, so this is what most class designers do.
        friend istack;

       public:
       // these are required by the standard.
        using iterator_category = std::bidirectional_iterator_tag;
        using value_type = ValueType;
        using reference = value_type &;

        // this is void because this is an iterator to an int/const int, not a class type.
        // `pointer` is only used in operator->(), but that syntax is illegal for this class.
        // thus, void is the only option.
        using pointer = void;

        // this is canonical and can be remembered verbatim.
        using difference_type = std::ptrdiff_t;

        // the implementation of the iterator let's us default these
        // I would explain why they can be defaulted, though.
        iter() = default;
        iter(const iter &) = default;
        iter &operator=(const iter &) = default;

        reference operator*() const {
            return *ptr_;
        }
        pointer operator->() const { /* does nothing */ }

        iter &operator++() {
            --ptr_; // we're going backwards through a vector, so going forwards is going backwards
            return *this;
        }

        // this is the canonical way to write post-increment in terms of pre-increment.
        // can be remembered and written verbatim.
        iter operator++(int) {
           auto self = *this;
            ++*this;
            return self;
        }

        iter &operator--() {
            ++ptr_; // we're going backwards through a vector, so going backwards is going forwards
            return *this;
        }
        // this is the canonical way to write post-decrement in terms of pre-decrement.
        // can be remembered and written verbatim.
        iter operator--(int) {
            auto self = *this;
            --*this;
            return self;
        }

        // C++20 style equality operator as a member function.
        // will automatically generate operator!=().
        // does a member-wise comparison using operator== and returns true only if all the members compare equal
        // this is exactly the semantics we need for such a simple class.
        bool operator==(const iter&) const = default;

       private:
        iter(value_type *base) : ptr_{base} {}

        // the implementation of the iterator is simple.
        // start at the base of the stack (based on ValueType, its either an int * or a const int *)
        // then, move what index you're looking at either forwards or backwards.
        value_type *ptr_;
    };

   public:
   // these are public typedefs required for an STL-compliant container.
   // the only logical difference between an iterator and a const-iterator is the mutability of its value type
   // hence we use a very simple template to reduce code duplication.
    using iterator = iter<int>; // value_type is int, mutable
    using const_iterator = iter<const int>; // value_type is const int, immutable

    // these are the canonical way of creating reverse_iterators for bidirectional ranges and greater.
    // can be written and remembered verbatim.
    using reverse_iterator = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;

    // other implementation details
    istack(std::initializer_list<int> il = {}) : base_{il} {}

    void push(int i) { base_.push_back(i); }
    int top() const { return base_.back(); }
    void pop() { base_.pop_back(); }

    // all in all there are 12 of these range functions.
    // 2 begin() variants (one is const-qualified)
    // 2 end() variants (one is const-qualified)
    // 1 cbegin(), 1 cend()
    // altogether 6 for forward traversal,
    // 6 for backwards traversal.
    iterator begin() { return iterator{base_.data() + base_.size() - 1}; }
    iterator end() { return iterator{base_.data() -1}; }
    const_iterator begin() const { return const_iterator{base_.data() + base_.size() - 1}; }
    const_iterator end() const { return const_iterator{base_.data() -1}; }
    const_iterator cbegin() const { return const_iterator{base_.data() + base_.size() - 1}; }
    const_iterator cend() const { return const_iterator{base_.data() -1}; }

    // these also can be remembered verbatim as this is the canonical way to write the reverse iterator range functions.
    reverse_iterator rbegin() { return reverse_iterator{end()}; }
    reverse_iterator rend() { return reverse_iterator{begin()}; }
    const_reverse_iterator rbegin() const {
        return const_reverse_iterator{end()};
    }
    const_reverse_iterator rend() const {
        return const_reverse_iterator{begin()};
    }
    const_reverse_iterator crbegin() const {
        return const_reverse_iterator{end()};
    }
    const_reverse_iterator crend() const {
        return const_reverse_iterator{begin()};
    }

   private:
   // implementation is a pointer to some memory of ints
   // followed by the size of the stack.
    std::vector<int> base_;
};


备份地址: 【bidirectional_iterator_tag模板