2

view::join(驚くべき) Ranges-v3 ライブラリの関数オブジェクトで問題が発生しました。私のクライアント コードは、範囲のコレクションの集計ビュー用の back メソッドの存在に依存しています (ランダム アクセス イテレータを大いに歓迎します)。

関連ドキュメントを確認したところ、メソッドは join_view クラス テンプレートのインスタンス化と互換性があるようですが、そのようbackにインスタンス化できませんでした。

#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

簡単に検査できるように、ライブバージョンを作成しました。

bidirectional をインスタンス化する運があった人はいますjoin_viewか? 基になるデータをコピーせずに同様の動作を実現する方法について何か提案はありますか?

4

1 に答える 1

2

Range-v3 のjoinビューは を満たしていますが、それ以上のものは満たしInputRangeていませんForward。これは、結合がどのように達成されるかに関係しています。内側の範囲を繰り返し処理している間、範囲をどこかに保存する必要があります。それはオブジェクトのメンバーのどこかにありjoin_viewます。つまり、join_view反復処理中に変更されます。そのため、 より強い範囲カテゴリをモデル化することはできませんInput

于 2017-03-15T21:34:23.323 に答える