#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模板】