Copyright © 2019 T. Zachary Laine
根据 Boost 软件许可证版本 1.0 发布。(参见随附文件 LICENSE_1_0.txt 或在 https://boost.ac.cn/LICENSE_1_0.txt 复制)
目录
编写 STL 迭代器、视图和容器是一项非常困难的工作。有很多地方可能出现细微的错误。它也很繁琐,当然这使得它容易出错。
迭代器有大量的 typedef 和操作,尽管给定迭代器的所有操作最多可以用四个操作(通常只有三个)来实现。编写所有其他操作会产生非常相似的代码,难以审查,并且几乎要求您为每个迭代器编写完整的测试。
编写视图类型,如 std::ranges 中的视图类型,也需要付出很多努力,考虑到视图类型的大部分 API 可以从 begin() 和 end() 派生。C++20 有一个模板可以完全做到这一点,即 std::ranges::view_interface;Boost.STLInterfaces 提供了一个对 C++20 之前的版本友好的实现。
由于不同编译器在实现其 C++20 视图适配器的 operator| 支持方式上存在不一致,因此尝试编写一个可移植到多个 C++ 版本,甚至可移植到 C++20 模式下构建的多个编译器上的视图适配器特别棘手。Boost.STLInterfaces 提供了一个类型 boost::stl_interfaces::range_adaptor_closure,它与 C++23 的 std::range_adaptor_closure 兼容,并且也适用于早期版本的 C++。Boost.STLInterfaces 还提供了帮助模板,使得编写具有 operator| 支持的视图适配器更加容易。
最令人畏惧的是编写一个符合标准中容器要求的类型或模板的任务。Boost.STLInterfaces 提供了另一个名为 sequence_container_interface 的模板,该模板大大减轻了实现和测试的负担。
![]() |
注意 |
|---|---|
提供了 |
这是该库的迭代器部分的一个例子。假设我们要创建一个随机访问迭代器,它表示一个任意长度的字符串,该字符串是通过重复一个较短的字符串构建的。我们称之为 repeated_chars_iterator。以下是它的实际应用:
repeated_chars_iterator first("foo", 3, 0); // 3 is the length of "foo", 0 is this iterator's position. repeated_chars_iterator last("foo", 3, 7); // Same as above, but now the iterator's position is 7. std::string result; std::copy(first, last, std::back_inserter(result)); assert(result == "foofoof");
标准库中没有能提供这种行为的东西,所以我们必须自己写。这个库旨在将我们从这样写(
struct repeated_chars_iterator { using value_type = char; using difference_type = std::ptrdiff_t; using pointer = char const *; using reference = char const; using iterator_category = std::random_access_iterator_tag; constexpr repeated_chars_iterator() noexcept : first_(nullptr), size_(0), n_(0) {} constexpr repeated_chars_iterator( char const * first, difference_type size, difference_type n) noexcept : first_(first), size_(size), n_(n) {} constexpr reference operator*() const noexcept { return first_[n_ % size_]; } constexpr value_type operator[](difference_type n) const noexcept { return first_[(n_ + n) % size_]; } constexpr repeated_chars_iterator & operator++() noexcept { ++n_; return *this; } constexpr repeated_chars_iterator operator++(int)noexcept { repeated_chars_iterator retval = *this; ++*this; return retval; } constexpr repeated_chars_iterator & operator+=(difference_type n) noexcept { n_ += n; return *this; } constexpr repeated_chars_iterator & operator--() noexcept { --n_; return *this; } constexpr repeated_chars_iterator operator--(int)noexcept { repeated_chars_iterator retval = *this; --*this; return retval; } constexpr repeated_chars_iterator & operator-=(difference_type n) noexcept { n_ -= n; return *this; } friend constexpr bool operator==( repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept { return lhs.first_ == rhs.first_ && lhs.n_ == rhs.n_; } friend constexpr bool operator!=( repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept { return !(lhs == rhs); } friend constexpr bool operator<( repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept { return lhs.first_ == rhs.first_ && lhs.n_ < rhs.n_; } friend constexpr bool operator<=( repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept { return lhs == rhs || lhs < rhs; } friend constexpr bool operator>( repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept { return rhs < lhs; } friend constexpr bool operator>=( repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept { return rhs <= lhs; } friend constexpr repeated_chars_iterator operator+(repeated_chars_iterator lhs, difference_type rhs) noexcept { return lhs += rhs; } friend constexpr repeated_chars_iterator operator+(difference_type lhs, repeated_chars_iterator rhs) noexcept { return rhs += lhs; } friend constexpr repeated_chars_iterator operator-(repeated_chars_iterator lhs, difference_type rhs) noexcept { return lhs -= rhs; } friend constexpr difference_type operator-( repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept { return lhs.n_ - rhs.n_; } private: char const * first_; difference_type size_; difference_type n_; };
(这有很多代码!)变成这样(
struct repeated_chars_iterator : boost::stl_interfaces::iterator_interface< #if !BOOST_STL_INTERFACES_USE_DEDUCED_THIS repeated_chars_iterator, #endif std::random_access_iterator_tag, char, char> { constexpr repeated_chars_iterator() noexcept : first_(nullptr), size_(0), n_(0) {} constexpr repeated_chars_iterator( char const * first, difference_type size, difference_type n) noexcept : first_(first), size_(size), n_(n) {} constexpr char operator*() const noexcept { return first_[n_ % size_]; } constexpr repeated_chars_iterator & operator+=(std::ptrdiff_t i) noexcept { n_ += i; return *this; } constexpr auto operator-(repeated_chars_iterator other) const noexcept { return n_ - other.n_; } private: char const * first_; difference_type size_; difference_type n_; };
这样就好多了。这两个 repeated_chars_iterator 的定义具有相同的语义和性能特征。第二个定义只是需要写更少的代码,并且编写第二个定义对初学者更友好。
![]() |
注意 |
|---|---|
Boost.STLInterfaces 的 |