c++ - range-v3:调整已经实现迭代器接口(interface)的自定义类(开始/结束)

标签 c++ iterator range-v3

我有一个实现beginend 的自定义容器。如何将此容器通过管道传输到 ranges-v3 View ?

std::vector 是可管道化的,所以我尝试以同样的方式管道化我的自定义类,但是没有为我的容器找到管道运算符。

我查看了文档,但除了重新实现带有 Range 接口(interface)的包装类之外,我找不到任何其他方法。我有多个这样的类,我相信这可能是一个相当常见的情况,所以我宁愿使用库提供的一些函数(或类基),但我无法从文档中弄清楚。

这是一个最小的例子:

#include <iostream>
#include <iterator>
#include <range/v3/all.hpp>

struct Test {
    struct iterator;
    struct sentinel {};
    int counter;
    Test() = default;
    iterator begin();
    sentinel end() const { return {}; }
    iterator begin() const;
};

struct Test::iterator {
    using value_type = int;
    using reference = int&;
    using pointer = int*;
    using iterator_category = std::input_iterator_tag;
    using difference_type = void;
    Test* test;
    iterator& operator++() {
        test->counter++;
        return *this;
    }
    iterator operator++(int) {
        auto it = *this;
        ++*this;
        return it;
    }
    int operator*() { return test->counter; }
    int operator*() const { return test->counter; }
    bool operator!=(const iterator& rhs) const {
        return rhs.test != test;
    }
    bool operator!=(sentinel) const {
        return true;
    }
};

Test::iterator Test::begin() { return iterator {this}; }
Test::iterator Test::begin() const { return iterator {const_cast<Test*>(this)}; }

int main() {
    auto container = Test();
    static_assert(ranges::range<Test>, "It is not a range");
    static_assert(ranges::viewable_range<Test>, "It is not a viewable range");
    auto rng = container | ranges::views::take(10);
    for (auto n : rng) { std::cerr << n << std::endl;}
    return 0;
}

这是我在使用这段代码时遇到的错误:

~/tmp/range$ g++ main.cpp -Irange-v3/include -o main 2>&1 | grep error
main.cpp:46:19: error: static assertion failed: It is not a range
main.cpp:47:19: error: static assertion failed: It is not a viewable range
range-v3/include/range/v3/functional/pipeable.hpp:63:53: error: no matching function for call to ‘ranges::pipeable_access::impl<ranges::views::view<ranges::make_pipeable_fn::operator()(Fun) const [with Fun = ranges::detail::bind_back_fn_<ranges::views::take_fn, int>]::_> >::pipe(Test&, ranges::views::view<ranges::make_pipeable_fn::operator()(Fun) const [with Fun = ranges::detail::bind_back_fn_<ranges::views::take_fn, int>]::_>&)’
main.cpp:48:10: error: ‘void rng’ has incomplete type
main.cpp:49:19: error: unable to deduce ‘auto&&’ from ‘rng’

最佳答案

这是我的解决方案:

template <typename T>                                                                                                                                                                                              
class ContainerView : public ranges::view_facade<ContainerView<T>> {                                                                                                                                              
    friend ranges::range_access;                                                                                                                                                                                   

    using iterator_type = decltype(std::declval<T>().begin());                                                                                                                                                     
    using value_type = decltype(*std::declval<iterator_type>());                                                                                                                                                   

    T* container_;                                                                                                                                                                                                 
    iterator_type it_;                                                                                                                                                                                             

    value_type read() const { return *it_; }                                                                                                                                                                       
    bool equal(ranges::default_sentinel_t) const {                                                                                                                                                                 
        return !(it_ != container_->end());                                                                                                                                                                        
    }                                                                                                                                                                                                              
    void next() { ++it_; }                                                                                                                                                                                         

   public:                                                                                                                                                                                                         
    ContainerView() = default;                                                                                                                                                                                     
    ContainerView(T& container)                                                                                                                                                                                    
        : container_(&container), it_(container_->begin()) {}                                                                                                                                                      
    using ranges::view_facade<ContainerView<T>>::begin;                                                                                                                                                            
    using ranges::view_facade<ContainerView<T>>::end;                                                                                                                                                              
};                                                                                                                                                                                                                 

int main() {                                                                                                                                                                                                       
    auto container = Test();                                                                                                                                                                                       
    auto view = ContainerView(container);                                                                                                                                                                          
    static_assert(ranges::range<decltype(view)>, "It is not a range");                                                                                                                                             
    static_assert(ranges::viewable_range<decltype(view)>,                                                                                                                                                          
                  "It is not a viewable range");                                                                                                                                                                   
    auto rng = view | ranges::views::take(10);                                                                                                                                                                     
    for (auto n : rng) {                                                                                                                                                                                           
        std::cerr << n << std::endl;                                                                                                                                                                               
    }                                                                                                                                                                                                              
    return 0;                                                                                                                                                                                                      
}

我不确定我是否重新实现了库中已经实现的东西。所以,我暂时不会将其标记为答案。如果有这样做的现有方法,请发表评论或发布新答案。

关于c++ - range-v3:调整已经实现迭代器接口(interface)的自定义类(开始/结束),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57639012/

相关文章:

c++ - 检查鼠标按钮是否在 C++ 中交换

C++迭代器做什么?

java - struts2 在迭代器标签中包含测试

c++ - range-v3 可以包含初始化列表上的工作吗?

c++ - constexpr 在运行时表现更差

c++ - int 和 float 中的 super 奇怪的 C++ 黑洞

c++ - 如何仅使用Iterator显示Vector的前10个元素?

c++11 - 基于范围的算法是否可以完全独立于(但针对任何)容器类型进行优化?

c++ - 明确的 range-v3 decltype 评估为无效?

c++ - 访问动态数组中的结构中的字符串变量时如何修复 "segmentation fault (core dumped)"错误