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

ofo*_*ofo 5 c++ iterator range-v3

我有一个自定义容器实现beginend. 如何将此容器通过管道传输到 range-v3 视图?

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

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

这是一个最小的例子:

#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;
}

Run Code Online (Sandbox Code Playgroud)

这是我使用此代码遇到的错误:

~/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’
Run Code Online (Sandbox Code Playgroud)

T.C*_*.C. 2

  • 为了建模sentinel_for,迭代器和哨兵必须在两个方向上使用==和进行比较。!=(在新世界中,输入迭代器没有必要相互比较。)您只提供了!=并且仅在一个方向上提供。
  • difference_type不能用于void输入迭代器。它必须是有符号整数类型,例如ptrdiff_t.

此外:

  • referenceoperator*应该是;的返回类型 它不必是引用类型。
  • viewable_range<Test>询问右值是否Test可见。由于您正在尝试查看左值,请考虑使用Test&.