X

曜彤.手记

随记,关于互联网技术、产品与创业

吉 ICP 备10004938号

《C++17 STL Cookbook》读书笔记(二)


接上篇。

Chapter 3: Iterators

迭代器类别

构建自己的可迭代范围
for (auto x : range) { code_block; }

将被扩展为如下类似代码:

{ 
  auto __begin = std::begin(range);
  auto __end   = std::end(range);
  for ( ; __begin != __end; ++__begin) { 
    auto x = *__begin; 
    code_block
  } 
}
class NumIterator {
  int i;
 public:
  explicit NumIterator(int position = 0) : i {position} {}
  int operator*() const { return i; }
  NumIterator& operator++() {
    ++i;
    return *this;
  }
  bool operator!=(const NumIterator& o) const { return i != o.i; }
};
class NumRange {
  int from;
  int to;
 public:
  NumRange(int from, int to) : from{from}, to{to} {}
  NumIterator begin() { return NumIterator{from}; }
  NumIterator end() { return NumIterator{to}; }
};
int main(int argc, char **argv) {
  for (const auto& v : NumRange{1, 11}) {
    std::cout << v << std::endl;
  }
  return 0;
}
使自定义迭代器符合 STL 的迭代器分类
namespace std {   
  template<>
  struct iterator_traits<NumIterator> {
    using iterator_category = std::forward_iterator_tag;  // iterator type;
    using value_type = int;  // value type the iterator iterates;
    // using difference_type = ...
    // using pointer = ...
    // using reference = ...
  };
}
使用迭代器适配器来填充容器
使用迭代器来实现算法
class FibIt {
  friend class FibRange;
  size_t i {0};
  size_t a {0};
  size_t b {1};
  explicit FibIt(size_t i_) : i{i_} {}  // hiding the special usage of this constructor;
 public:
  FibIt() = default;
  size_t operator*() const { return b; }
  FibIt& operator++() {
    const size_t old_b {b};
    b += a;
    a = old_b;
    ++i;
    return *this;
  }
  bool operator!=(const FibIt& o) const { return i != o.i; }
};

template<>
struct std::iterator_traits<FibIt> {
  using iterator_category = std::forward_iterator_tag;
  using value_type = size_t;
};

class FibRange {
  size_t end_n;
 public:
  FibRange(size_t end_n_) : end_n(end_n_) {}
  FibIt begin() const { return FibIt{}; }
  FibIt end() const { return FibIt{end_n}; }
};

int main(int argc, char **argv) {
  for (const size_t i : FibRange(10)) {
    std::cout << i << std::endl;
  }
  return 0;
}
使用反向迭代器
int main(int argc, char **argv) {
  std::list li {1, 2, 3};
  std::copy(
    std::rbegin(li), 
    std::rend(li), 
    std::ostream_iterator<int>(std::cout, ", "));
  // mimic backward iterator with forward iterator;
  std::copy(
    std::make_reverse_iterator(std::end(li)), 
    std::make_reverse_iterator(std::begin(li)),  
    std::ostream_iterator<int>(std::cout, ", "));
  return 0;
}

使用 Sentinel 控制迭代器的遍历
class cstringIterSentinel {};
class cstringIter {
  const char* s {nullptr};
 public:
  explicit cstringIter(const char* str) : s{str} {}
  char operator*() const { return *s; }
  cstringIter& operator++() {
    ++s;
    return *this;
  }
  bool operator!=(const cstringIterSentinel) const {
    return s != nullptr && *s != '\0';  // termination condition;
  }
};

class cstringRange {
  const char* s {nullptr};
 public:
  cstringRange(const char* str) : s {str} {}
  cstringIter begin() const { return cstringIter{s}; } 
  cstringIterSentinel end() const { return {}; }
};

int main(int argc, char **argv) {
  if (argc < 2) { exit(EXIT_FAILURE); }
  for (char c : cstringRange(argv[1])) {
    std::cout << c << std::endl;
  }
  return 0;
}
检查迭代器的有效性
实现一个 zip() 迭代器
class ZipIter {
  using itType = std::vector<double>::iterator;
  itType itX;
  itType itY;
 public:
  explicit ZipIter(itType itX, itType itY) : itX(itX), itY(itY) {}
  ZipIter& operator++() {
    ++itX;
    ++itY;
    return *this;
  }
  bool operator!=(const ZipIter& o) const { return itX != o.itX && itY != o.itY; }
  bool operator==(const ZipIter& o) const { return !operator!=(o); }
  std::pair<double, double> operator*() const { return {*itX, *itY}; }
};

template<>
struct std::iterator_traits<ZipIter> {
  using iterator_category = std::forward_iterator_tag;
  using value_type = std::pair<double, double>;
  using difference_type = long int;
};

class Zipper {
  using vecType = std::vector<double>;
  vecType &vecX;
  vecType &vecY;
 public:
  Zipper(vecType &vecX, vecType &vecY) : vecX(vecX), vecY(vecY) {}
  auto begin() const { return ZipIter{std::begin(vecX), std::begin(vecY)}; }
  auto end() const { return ZipIter{std::end(vecX), std::end(vecY)}; }
};

int main(int argc, char **argv) {
  std::vector x {1.0, 2.0, 3.0};
  std::vector y {2.0, 3.0, 4.0};
  Zipper z {x, y};
  const auto dotProduct = std::accumulate(
    std::begin(z), 
    std::end(z), 
    0.0,
    [](double sum, const auto &p) {
      return sum + p.first * p.second;
    });
  std::cout << dotProduct << std::endl;
  return 0;
}

Chapter 4: Lambda Expressions

使用 lambda 表达式

int main(int argc, char **argv) {
  auto x ([]() { return 1; });
  auto y ([] { return 2; });
  auto plus ([](auto l, auto r) { return l + r; });

  // closure variable;
  auto counter ([count = 0]() mutable { return ++count; });
  std::cout << counter() << std::endl;

  // closure reference;
  int v {10};
  auto incrementer ([&v] { ++v; });

  // currying;
  auto plusTen ([=](int x) { return plus(10, x); });
  std::cout << plusTen(10) << std::endl;

  // constexpr;
  constexpr int i = 100;
  constexpr int j = ([i]() constexpr { return i + 10; })();
  int arr[j] = {1, 2, 3};
  return 0;
}
使用 std::function 为 lambda 提供多态支持
template<typename T>
static auto consumer (T& container) {
  return [&](auto value) {
    container.push_back(value);
  };
}
int main(int argc, char **argv) {
  std::deque<int> d;
  std::list<int> l;
  std::vector<int> v;
  const std::vector<std::function<void(int)>> consumers {
    consumer(d), consumer(l), consumer(v)
  };
  for (size_t i {0}; i < 10; ++i) {
    for (auto& consume : consumers) {
      consume(i);
    }
  }
  return 0;
}
函数连接(流水线拼接)
template<typename T, typename ...Ts>
auto concat(T t, Ts ...ts) {
  if constexpr (sizeof...(ts) > 0) {
    return [=](auto ...params) {
      return t(concat(ts...)(params...));
    };
  } else {
    return t;
  }
}

int main(int argc, char **argv) {
  auto twice ([](int i) { return i * 2; });
  auto thrice ([](int i) { return i * 3; });
  auto combined (concat(twice, thrice, std::plus<int>{}));
  std::cout << combined(2, 3) << std::endl;
  return 0;
}
使用“逻辑与”创建复杂谓词(Predicates)结构
template<typename A, typename B, typename F>
auto combine(F binaryFunc, A a, B b) {
  return [=](auto param) {
    return binaryFunc(a(param), b(param));
  };
}
int main(int argc, char **argv) {
  std::cout << combine(
    std::logical_and<>{},
    [](int v) { return v > 0; }, 
    [](int v) { return v <= 100; })(10);
  return 0;
}
一个函数应用于多个参数 / 多个函数应用一个参数
template<typename ...Ts>
static auto multicall(Ts ...funcs) {
  return [=](auto x) {
    (void) std::initializer_list<int>{
      ((void) funcs(x), 0)...
    };
  };
}
template<typename T, typename ...Ts>
static auto forEach(T f, Ts ...xs) {
  (void) std::initializer_list<int>{
    ((void) f(xs), 0)...
  };
}

int main(int argc, char **argv) {
  forEach([](int x) { std::cout << x << std::endl; }, 1, 2, 3);
  multicall(
    [](int x) { std::cout << x << std::endl; },
    [](int x) { std::cout << x + 10 << std::endl; },
    [](int x) { std::cout << x + 20 << std::endl; }
  )(10);
  return 0;
}
实现 std::transform_if
template<typename T>
auto map(T fn) {
  return [=] (auto reduceFn) {
    return [=] (auto accum, auto input) {
      return reduceFn(accum, fn(input));
    };
  };
}
template<typename T>
auto filter(T predicate) {
  return [=] (auto reduceFn) {
    return [=] (auto accum, auto input) {
      if (predicate(input)) {
        return reduceFn(accum, input);
      } else {
        return accum;
      }
    };
  };
}
int main(int argc, char **argv) {
  std::istream_iterator<int> it {std::cin};
  std::istream_iterator<int> endIt;
  auto copyAndAdvance (
    [](auto it, auto input) {
      *it = input;
      return ++it;  // no-op for std::ostream_iterator to be incremented;
  });
  std::accumulate(it, endIt,
    std::ostream_iterator<int>{std::cout, ", "},
    filter([](int i) { return i % 2 == 0; })(
      map([](int i) { return i * 2; })(copyAndAdvance)));
  return 0;
}
实现两个集合的“笛卡尔积(Cartesian Product)”

static void print(int x, int y) {
  std::cout << "(" << x << ", " << y << ")\n";
}

int main(int argc, char **argv) {
  constexpr auto callCart (
    [=](auto f, auto x, auto ...rest) constexpr {
      (void) std::initializer_list<int>{
        (((x < rest) ? (void) f(x, rest) : (void)0), 0)...
      };
    }
  );
  constexpr auto cartesian ([=](auto ...xs) constexpr {
    return [=] (auto f) constexpr {
      (void) std::initializer_list<int>{
        ((void) callCart(f, xs, xs...), 0)...
      };
    };
  });
  constexpr auto printCart (cartesian(1, 2, 3));
  printCart(print);
  return 0;
}


这是文章底线,下面是评论
  暂无评论,欢迎勾搭 :)