2017-03-15 10 views
2

(놀라운) Ranges-v3 라이브러리의 view::join 함수 객체로 약간의 어려움을 겪었습니다. 내 클라이언트 코드는 일련의 범위 컬렉션에 대한 백 뷰 (back method)의 존재 여부에 따라 달라지며 (무작위 액세스 반복자에 크게 감사 할 것입니다.)Ranges-v3 view :: join으로 양방향성 유지하기

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_viewBoundedView 또는 BidirectionalView 개념 (또는 둘 다)을 위반합니다. 나는 이전의 것을 가능한 빨리 제거 할 수 있었다. 이 경우

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? 기본 데이터를 복사하지 않고 비슷한 동작을 달성 할 수있는 방법에 대한 제안은 무엇입니까?

답변

2

범위 -v3의 join보기는 InputRange을 만족하지만 Forward 또는 그보다 강한 것은 아닙니다. 조인이 수행되는 방법과 관련이 있습니다. 내부 범위를 반복하면서 범위를 어딘가에 저장해야합니다. 그 어딘가는 join_view 개체의 멤버입니다. 즉, 반복 할 때 join_view이 돌연변이됩니다. 따라서 Input보다 강력한 범위 카테고리는 모델링 할 수 없습니다.