Iterator

Upper Bound

Note that std::upper_bound(x.begin(), x.end(), val) finds an element which is greater than the val. However, std::lower_bound(x.begin(), x.end(), val), finds an element which is greater or equal to the val.

#include <iostream>
#include <deque>
#include <algorithm>

int main(int argc, char *argv[]) {
  std::deque<int> v{1,2,3,4,5,7,10};

  auto x = 5;
  auto pos1 = std::upper_bound(v.begin(), v.end(), x);
  std::cout << *pos1 << "\n";

  auto pos2 = std::lower_bound(v.begin(), v.end(), x);
  std::cout << *pos2 << "\n";

  // 7
  // 5
}

Insert an Element into a Sorted List

#include <iostream>
#include <deque>
#include <algorithm>
#include <range/v3/view/all.hpp>


int main(int argc, char *argv[]) {
  std::deque<int> v{1,2,3,4,5,7,10};

  auto x = 8;
  auto pos = std::upper_bound(v.begin(), v.end(), x);
  v.insert(pos, x);
  std::cout << ranges::views::all(v) << "\n";
  // [1,2,3,4,5,7,8,10]
}

Erase an Element in a Sorted List

#include <iostream>
#include <deque>
#include <algorithm>
#include <range/v3/view/all.hpp>


int main(int argc, char *argv[]) {
  std::deque<int> v{1,2,3,4,5,7,10};

  auto x = 7;
  auto pos = std::lower_bound(v.begin(), v.end(), x);
  v.erase(pos);
  std::cout << ranges::views::all(v) << "\n";
  // [1,2,3,4,5,10]
}

Reverse Range-based for Loop

// via boost
// $ g++ --std=c++14 -Wall -Werror -g -O3 reverse.cpp
// $ ./a.out
// dlrow olleh

#include <iostream>
#include <string>
#include <boost/range/adaptor/reversed.hpp>

using namespace boost;

int main(int argc, char *argv[]) {
  std::string in = "hello world";
  std::string out;
  for (const auto &c : adaptors::reverse(in)) {
      out += c;
  }
  std::cout << out << "\n";
}

Customize an Iterator

// $ g++ -std=c++17 -Wall -Werror -g -O3 a.cc

#include <iostream>
#include <memory>

template <typename T>
class Array
{
 public:
  class iterator
  {
    public:
      iterator(T *ptr) : ptr_{ptr} {}
      iterator operator++() { auto i = *this; ++ptr_; return i; }
      iterator operator++(int) { ++ptr_; return *this;};
      T &operator*() { return *ptr_; }
      T *operator->() { return ptr_; }
      bool operator==(const iterator &rhs) { return ptr_ == rhs.ptr_; }
      bool operator!=(const iterator &rhs) { return ptr_ != rhs.ptr_; }
    private:
      T *ptr_;
  };

  class const_iterator
  {
    public:
     const_iterator(T *ptr) : ptr_{ptr} {}
     const_iterator operator++() { auto i = *this; ++ptr_; return i; }
     const_iterator operator++(int) { ++ptr_; return *this; }
     const T &operator*() const { return *ptr_; }
     const T *operator->() const { return ptr_; }
     bool operator==(const const_iterator &rhs) { return ptr_ == rhs.ptr_; }
     bool operator!=(const const_iterator &rhs) { return ptr_ != rhs.ptr_; }
    private:
     T *ptr_;
  };

  Array(size_t size) : size_(size), data_{std::make_unique<T[]>(size)} {}
  size_t size() const { return size_; }
  T &operator[](size_t i) { return data_[i]; };
  const T &operator[](size_t i) const { return data_[i]; }
  iterator begin() { return iterator(data_.get()); }
  iterator end() { return iterator(data_.get() + size_); }
  const_iterator cbegin() const { return const_iterator(data_.get()); }
  const_iterator cend() const { return const_iterator(data_.get() + size_); }

 private:
  size_t size_;
  std::unique_ptr<T[]> data_;
};



int main(int argc, char *argv[])
{
  Array<double> points(2);
  points[0] = 55.66;
  points[1] = 95.27;
  for (auto &e : points) {
    std::cout << e << "\n";
  }
  for (auto it = points.cbegin(); it != points.cend(); ++it) {
    std::cout << *it << "\n";
  }
}

Iterate an Internal Vector

#include <iostream>
#include <utility>
#include <vector>

template<typename T>
class Vector {
 public:
  using iterator = typename std::vector<T>::iterator;
  using const_iterator = typename std::vector<T>::const_iterator;

  inline iterator begin() noexcept {return v.begin();}
  inline iterator end() noexcept {return v.end();}
  inline const_iterator cbegin() const noexcept {return v.cbegin();}
  inline const_iterator cend() const noexcept {return v.cend();}

  template<class... Args>
  auto emplace_back(Args&&... args) {
      return v.emplace_back(std::forward<Args>(args)...);
  }
 private:
  std::vector<T> v;
};


int main(int argc, char *argv[]) {
  Vector<int> v;
  v.emplace_back(1);
  v.emplace_back(2);
  v.emplace_back(3);

  for (auto &it : v) {
      std::cout << it << std::endl;
  }
  return 0;
}

Iterate a file

// $ g++ -std=c++17 -Wall -Werror -g -O3 a.cc
// $ ./a.out file

#include <iostream>
#include <iterator>
#include <fstream>
#include <string>

class line : public std::string {};

std::istream &operator>>(std::istream &is, line &l)
{
  std::getline(is, l);
  return is;
}

class FileReader
{
 public:
  using iterator = std::istream_iterator<line>;
  inline iterator begin() noexcept { return begin_; }
  inline iterator end() noexcept { return end_; }

 public:
  FileReader(const std::string path) : f_{path}, begin_{f_} {}
  friend std::istream &operator>>(std::istream &, std::string &);

 private:
  std::ifstream f_;
  iterator begin_;
  iterator end_;
};

int main(int argc, char *argv[])
{
  FileReader reader(argv[1]);
  for (auto &line : reader) {
    std::cout << line << "\n";
  }
}

Position after Erasing

// deque
    #include <iostream>
    #include <deque>
    #include <range/v3/view/all.hpp>

    int main(int argc, char *argv[]) {
      std::deque<int> q{1, 2, 3, 4, 5};
      auto it = q.begin() + 2;

      std::cout << *it << "\n";
      std::cout << ranges::views::all(q) << "\n";

      q.erase(it);
      std::cout << *it << "\n";
      std::cout << ranges::views::all(q) << "\n";

      // output
      //   3
      //   [1,2,3,4,5]
      //   4
      //   [1,2,4,5]
    }
#include <iostream>
#include <vector>
#include <range/v3/view/all.hpp>

int main(int argc, char *argv[]) {
  std::vector<int> v{1, 2, 3, 4, 5};
  auto it = v.begin() + 2;

  std::cout << *it << "\n";
  std::cout << ranges::views::all(v) << "\n";

  v.erase(it);
  std::cout << *it << "\n";
  std::cout << ranges::views::all(v) << "\n";

  // output
  //   3
  //   [1,2,3,4,5]
  //   4
  //   [1,2,4,5]
}
#include <iostream>
#include <list>
#include <range/v3/view/all.hpp>

int main(int argc, char *argv[]) {
  std::list<int> l{1, 2, 3, 4, 5};
  auto it = l.begin();
  ++it;

  std::cout << *it << "\n";
  std::cout << ranges::views::all(l) << "\n";

  // Note that Iterators, pointers and references referring to elements
  // removed by the function are invalidated. This is an example to show
  // that an iterator do not point to the next element after erasing.
  l.erase(it);
  std::cout << *it << "\n";
  std::cout << ranges::views::all(l) << "\n";
  // output
  //   2
  //   [1,2,3,4,5]
  //   2
  //   [1,3,4,5]
}

Vector Comparision

Note that the comparision operators are removed in C++20 (see [doc](https://en.cppreference.com/w/cpp/container/vector)). Therefore, using a lambda function as compare function is better than using default comparision when elements are not builtin types or has its own comparision operators.

#include <iostream>
#include <vector>

int main(int argc, char *argv[]) {
    std::vector<int> v1{5,2};
    std::vector<int> v2{2,3,4};
    std::cout << (v1 < v2) << "\n";
    // output: 0
}