Boost C++ 库

...世界上最受推崇和专业设计的 C++ 库项目之一。 Herb SutterAndrei Alexandrescu, C++ 编码标准

PrevUpHomeNext

第 36 章。 Boost.STLInterfaces

Zach Laine

根据 Boost 软件许可协议 1.0 版分发。(请参阅随附文件 LICENSE_1_0.txt 或访问 https://boost.ac.cn/LICENSE_1_0.txt

目录

简介
本库与 Boost.Iterator 的关系
v1v2 命名空间以及 C++20 概念的使用
教程:iterator_interface
教程:view_interface
教程:sequence_container_interface
教程:reverse_iterator
教程:视图适配器
教程:closureadaptor
教程:bind_back() 和更复杂的视图适配器
示例
随机访问迭代器
可变和常量迭代器的互操作性
Zip 迭代器 / 代理迭代器
重新实现 back_insert_iterator
重新实现 reverse_iterator
编译器支持
参考
头文件
原理

编写 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 的模板,它大大减轻了实现和测试负担。

[Note] 注意

提供了 C++20 版本的 iterator_interfacesequence_container_interface(C++20 提供了 std::view_interface)。这些是使用 C++20 概念约束的模板。这些位于 boost::stl_interfaces::v2 命名空间中。还有一个 C++23 版本的 iterator_interface,它使用推导 this 而不是 CRTP。如果您什么都不做,您将获得最新的 vN 内联命名空间,具体取决于您的编译器的语言支持。

一个快速示例

这是一个库的迭代器部分的示例。假设我们想要创建一个随机访问迭代器,它表示由重复较短字符串构造的任意长度的字符串。我们称这个迭代器为 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 的这两个定义具有相同的语义和性能特征。只是编写第二个定义的代码要少得多,并且编写第二个定义对新手更友好。

[Note] 注意

Boost.STLInterfaces 的 iterator_interface 实现了模拟 C++20 迭代器概念的迭代器。


PrevUpHomeNext