You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何C++标准库未提供简化自定义输入范围创建的工具?

为什么C++标准库没有简化自定义输入范围创建的工具?

在Python中创建自定义输入迭代器十分便捷,仅需实现__next__()方法。而C++的迭代器协议复杂得多:可迭代对象需实现begin()和end()方法,编写嵌套迭代器类,定义value_type、difference_type等关联类型,还要重载前置/后置++、*、==(需支持与自身及哨位比较)等运算符。因此创建自定义输入范围并不方便,尽管这类范围在解析器、数据库操作等场景中十分适用。

既然创建自定义输入范围的多数操作都是重复性的,为何C++标准库未提供简化其创建的工具?我们可以提出这样的解决方案:

  • 规定符合input_range的可迭代对象必须拥有next()方法,返回std::optional<elem_type>类型的值,其中elem_type为可迭代对象的元素类型;当可迭代对象耗尽时,bool(value)为false,否则value.value()即为下一个元素的值。
  • 为标准库添加可迭代对象适配器,自动实现所需的C++迭代器协议,示例代码如下:
template <typename iterable_type>
class TIterableWrapper
{
private:
    iterable_type&             iterable;
    using                      elem_type = typename decltype(std::declval<iterable_type>().next())::value_type;
    std::optional<elem_type>   value;

public:
    TIterableWrapper(iterable_type& _iterable) : iterable(_iterable)
    {
        value = iterable.next();
    }

    class iterator
    {
    private:
        TIterableWrapper*   wrapper_ptr;

        iterator(TIterableWrapper* _wrapper_ptr) : wrapper_ptr(_wrapper_ptr)
        {
        }
        friend class TIterableWrapper<iterable_type>;
    public:
        using iterator_category = std::input_iterator_tag;
        using value_type        = elem_type;
        using reference         = value_type&;
        using difference_type   = std::ptrdiff_t;

        iterator& operator++()
        {
            wrapper_ptr->value = wrapper_ptr->iterable.next();
            return (*this);
        }

        void operator++(int)
        {
           ++(*this);
        }

        const reference& operator*() const
        {
            return  wrapper_ptr->value.value();
        }

        bool operator==(const iterator& rhs) const
        {
            return this == &rhs;
        }

        bool operator==(std::default_sentinel_t) const
        {
            return !bool(*wrapper_ptr);
        }
    };

    operator bool() const
    {
        return bool(value);
    }

    auto begin() noexcept
    {
        return iterator(this);
    }

    auto end() const noexcept
    {
        return std::default_sentinel;
    }
};

与istream_view不同,该适配器调用begin()时不会触发可迭代对象的next()方法,这使得我们可以编写类似以下示例的代码,无需担心丢失可迭代对象的元素,避免了istream或std::generator等输入范围与std::views配合时的问题:

class TMyIterable
{
private:
    int  count;
    int  iter_number{ 0 };
public:
    TMyIterable(int _count) : count(_count)
    {
    }

    std::optional<int> next()
    {
        return (iter_number < count) ? std::optional<int>(iter_number++) : std::nullopt;
    }
};

void TEST_TIterableWrapper()
{
    TMyIterable                     my_iterable(10);
    TIterableWrapper<TMyIterable>   my_iterable_wrapper(my_iterable);
    auto                            view1 = my_iterable_wrapper | std::views::take(5);
    auto                            view2 = my_iterable_wrapper | std::views::take(5);
    std::ranges::copy(view1, std::ostream_iterator<int>(std::cout, ", "));
    std::cout << "\n";
    std::ranges::copy(view2, std::ostream_iterator<int>(std::cout, "- "));
}

如此一来,C++中创建自定义输入范围的便捷性将不输于Python。

内容的提问来源于stack exchange,提问作者Pavel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 07:20:06