28 Ağustos 2020 Cuma

ranges Kütüphanesi

Giriş
C++20 ile geliyor. Temel amacı lazy evaluation

Neden Aynı Algoritma İsimleri
STL içinde iterator alan algoritma isimleri aynı zamanda ranges içinde de var. Sebebi STL algoritmalarını iterator kullanması, ancak ranges iterator dönmüyor, sentinel denen bir nesne dönüyor. Dolayısıyla şu kod derlenmez
#include <ranges>
#include <numeric>
#include <iostream>

int main() {
  auto rng = std::ranges::istream_view<int>(std::cin);
  std::cout << std::accumulate(std::ranges::begin(rng), std::ranges::end(rng), 0);
}
Açıklaması şöyle
The problem is that the end of a C++ range is not, in the general case, an iterator, but rather, a sentinel. A sentinel can have a different type than an iterator and admit fewer operations - as, generally speaking, you mostly need to compare against it to know you've reached the end of the range, and may not be allowed to just work with it like any iterator.
Açıklaması şöyle
While a lot of algorithms added corresponding overloads into std::ranges, the ones in <numeric> were left out. There is a std::accumulate but there is no std::ranges::accumulate
Dolayısıyla C++ içinde birbirine uyumsuz stream, iterator nesneleri yanında bir range nesnesi geldi.

Generators
ranges Generators yazısına taşıdım.

std::ranges::contiguous_range metodu
Parametrenin std::ranges::random_access_range olması gerekir. Tanımı şöyle
template<class T>
concept contiguous_range =
  ranges::random_access_range<T> &&
  std::contiguous_iterator<ranges::iterator_t<T>> &&
  requires(T& t) {
    { ranges::data(t) } ->
      std::same_as<std::add_pointer_t<ranges::range_reference_t<T>>>;
  };
Örnek
Şöyle yaparız
struct ntbs_sentinel {
  bool operator==(char const* p) const {
    return *p == '\0';
  }
};

struct ntbs {
  char const* p;
  char const* begin() const { return p; }
  ntbs_sentinel end() const { return {}; }
};

static_assert(std::ranges::contiguous_range<ntbs>);
static_assert(!std::ranges::sized_range<ntbs>);
std::ranges::fill metodu
Şöyle yaparız.
#include <algorithm>
#include <cassert>
#include <span>

namespace ranges = std::ranges;

int main()
{
  int arr[] {1, 7, 3, 2, 0, 5, 0, 8};

  const std::span spn{arr};
  ranges::fill(spn, 173);               // this compiles

  assert(ranges::count(arr, 173) == 8); // passes
}
std::ranges::find metodu
İki tane overload edilmiş hali var. Bunlar şöyle
namespace ranges {
  template<input_­iterator I, sentinel_­for<I> S, class T, class Proj = identity>
    requires indirect_­binary_­predicate<ranges::equal_to, projected<I, Proj>, const T*>
    constexpr I find(I first, S last, const T& value, Proj proj = {});

  template<input_­range R, class T, class Proj = identity>
    requires indirect_­binary_­predicate<ranges::equal_to,
                                       projected<iterator_t<R>, Proj>, const T*>
    constexpr borrowed_iterator_t<R>
      find(R&& r, const T& value, Proj proj = {});
}
std::ranges::istream_view metodu
Açıklaması şöyle
There is a utility to wrap a C++20 range into a C++17-compatible one: views::common
istream_view's iterators aren't copyable, and in C++17 all iterators must be. So there isn't really a way to provide C++17-compatible iterators based on istream_view.
Örnek
Şöyle yaparız
auto rng = std::ranges::istream_view<int>(ints) | std::views::common;
std::cout << std::accumulate(rng.begin(), rng.end(), 0);
std::ranges::range metodu
Örnek
Şöyle yaparız.
template<typename T>
concept nested_range = std::ranges::range<T> && 
std::ranges::range<std::ranges::range_value_t<T>>
Açıklaması şöyle
If you want to ask if a type is a range which itself contains a range, that's simply applying the std::range type twice
std::ranges::swap metodu
Örnek
Şöyle yaparız
#include <concepts>
#include <iostream>

struct dummy {
  friend void swap(dummy& a, dummy& b) {
    std::cout << "ADL" << std::endl;
  }
};

int main()
{
  int a{};
  int b{};
  dummy c{};
  dummy d{};
  std::ranges::swap(a, b);
  std::ranges::swap(c, d); // Ok. Prints "ADL" on console.
}


Hiç yorum yok:

Yorum Gönder