使用Ranges-v3视图保留双向性:: join

时间:2017-03-15 20:49:21

标签: c++ c++14 range-v3

我遇到了(惊人的)Ranges-v3库的view::join函数对象的一些困难。我的客户端代码依赖于back方法的存在(并且会非常感谢随机访问迭代器),用于范围集合的聚合视图。

在审核relevant documentation之后,似乎back方法与join_view类模板的瞬时兼容,但我无法将其实例化。

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

struct Foo{
    std::vector<int> i = {1,2,3,4};
    const std::vector<int>& data() const { return this->i; }
};

int main(){
    std::vector< Foo > foos = { Foo(), Foo(), Foo() };

    auto data = []( auto&& foo ){ return foo.data() | ranges::view::all; };
    auto flat = foos | ranges::view::transform(data) | ranges::view::join;
    std::cout << flat.back() << std::endl; // compiler error
}

编译器错误消息的相关位是:

main.cpp:17:28: error: no matching function for call to 'ranges::v3::join_view<ranges::v3::transform_view<ranges::v3::range<__gnu_cxx::__normal_iterator<Foo*, std::vector<Foo> >, __gnu_cxx::__normal_iterator<Foo*, std::vector<Foo> > >, main()::<lambda(auto:1&&)> >, void>::back()'

 std::cout << flat.back() << std::endl; // compiler error

/usr/local/include/range/v3/range_interface.hpp:116:34: note: candidate: template<class D, int _concept_requires_115, typename std::enable_if<((_concept_requires_115 == 43) || ((std::is_same<D, ranges::v3::join_view<ranges::v3::transform_view<ranges::v3::range<__gnu_cxx::__normal_iterator<Foo*, std::vector<Foo> >, __gnu_cxx::__normal_iterator<Foo*, std::vector<Foo> > >, main()::<lambda(auto:1&&)> >, void> >() && ranges::v3::concepts::models<ranges::v3::concepts::BoundedView, T>()) && ranges::v3::concepts::models<ranges::v3::concepts::BidirectionalView, T>())), int>::type <anonymous> > ranges::v3::range_reference_t<D> ranges::v3::range_interface<Derived, Inf>::back() [with D = D; int _concept_requires_115 = _concept_requires_115; typename std::enable_if<((_concept_requires_115 == 43) || ((std::is_same<D, Derived>() && ranges::v3::concepts::models<ranges::v3::concepts::BoundedView, D>()) && ranges::v3::concepts::models<ranges::v3::concepts::BidirectionalView, D>())), int>::type <anonymous> = <enumerator>; Derived = ranges::v3::join_view<ranges::v3::transform_view<ranges::v3::range<__gnu_cxx::__normal_iterator<Foo*, std::vector<Foo> >, __gnu_cxx::__normal_iterator<Foo*, std::vector<Foo> > >, main()::<lambda(auto:1&&)> >, void>; bool Inf = false]

         range_reference_t<D> back()

/usr/local/include/range/v3/range_interface.hpp:115:17: error: no type named 'type' in 'struct std::enable_if<false, int>'

                 CONCEPT_REQUIRES_(Same<D, Derived>() && BoundedView<D>() && BidirectionalView<D>())>

第一个要求似乎是强制正确使用CRTP,这是令人满意的。因此,join_view违反了BoundedViewBidirectionalView概念(或两者)。我能够迅速消除前者作为可能性。

auto flat = foos 
  | ranges::view::transform(data) 
  | ranges::view::join 
  | ranges::view::bounded;
std::cout << flat.back() << std::endl; // compiler error

在这种情况下,flat满足BoundedView概念,但错误消息保持不变。

为了验证BidirectionalView,我尝试检查join_view的迭代器,但遇到(可疑的是)是一个错误。

auto it = flat.begin();
std::cout << *it << std::endl; // correct
++it; std::cout << *it << std::endl; // correct
--it; std::cout << *it << std::endl; // doesn't actually decrement
auto other = --it;
std::cout << *it << ' ' << *other << std::endl; // also doesn't decrement

为了便于检查,我写了live version

有没有人运气实例化双向join_view?有关如何在不复制基础数据的情况下实现类似行为的任何建议吗?

1 个答案:

答案 0 :(得分:2)

范围-v3&#39; join视图满足InputRange,但不满足Forward或更强。它与连接的完成方式有关。迭代内部范围时,范围需要存储在某处。那个地方是join_view对象的成员。换句话说,join_view在您迭代它时会发生变异。因此,它无法模拟任何强于Input的范围类别。