为何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
相关产品推荐
相关产品推荐

