1

我在使用std::views::filter连接的流/范围时遇到了麻烦。我不知道这里到底出了什么问题。我想元素可能不会以正确的(复制/移动)语义传递,应该使用引用包装器或其他东西。

#include <ranges>

int main(int argc_, char* argv_[]) {
  auto r1 = std::views::single(42);

  // create a nested range to have something to join
  auto r2 = r1 | std::views::transform([](auto& e_) { return std::ranges::single_view{e_}; });

  auto r3 = r2 | std::views::join;

  // case #1: single -> transform -> join -> filter
  {
    auto r4a = r3 | std::views::filter([](auto e_) { return true; });

    // ERROR: missing 'iterator_category'
    for (int i : r4a) { }
  }

  // case #2: single -> transform -> join -> transform
  {
    auto r4b = r3 | std::views::transform([](auto e) { return e; });

    // OK: it compiles
    for (int i : r4b) { }
  }

  return 0;
}                                                                                          

第 17 行给出了这个错误信息:

$ g++ --version
g++ (Rev6, Built by MSYS2 project) 10.2.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ g++ test.cpp -g -std=c++20
In file included from test.cpp:1:
d:/Programs/msys64/mingw64/include/c++/10.2.0/ranges: In instantiation of 'static constexpr auto std::ranges::filter_view<_Vp, _Pred>::_Iterator::_S_iter_cat() [with _Vp = std::ranges::join_view<std::ranges::transform_view<std::ranges::single_view<int>, main(int, char**)::<lambda(auto:13&)> > >; _Pred = main(int, char**)::<lambda(auto:14)>]':
d:/Programs/msys64/mingw64/include/c++/10.2.0/ranges:1473:48:   required from 'struct std::ranges::filter_view<std::ranges::join_view<std::ranges::transform_view<std::ranges::single_view<int>, main(int, char**)::<lambda(auto:13&)> > >, main(int, char**)::<lambda(auto:14)> >::_Iterator'
test.cpp:17:20:   required from here
d:/Programs/msys64/mingw64/include/c++/10.2.0/ranges:1455:10: error: no type named 'iterator_category' in 'struct std::iterator_traits<std::ranges::join_view<std::ranges::transform_view<std::ranges::single_view<int>, main(int, char**)::<lambda(auto:13&)> > >::_Iterator<false> >'
 1455 |    using _Cat = typename iterator_traits<_Vp_iter>::iterator_category;
      |          ^~~~
d:/Programs/msys64/mingw64/include/c++/10.2.0/ranges:1456:18: error: no type named 'iterator_category' in 'struct std::iterator_traits<std::ranges::join_view<std::ranges::transform_view<std::ranges::single_view<int>, main(int, char**)::<lambda(auto:13&)> > >::_Iterator<false> >'
 1456 |    if constexpr (derived_from<_Cat, bidirectional_iterator_tag>)
      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
d:/Programs/msys64/mingw64/include/c++/10.2.0/ranges:1458:23: error: no type named 'iterator_category' in 'struct std::iterator_traits<std::ranges::join_view<std::ranges::transform_view<std::ranges::single_view<int>, main(int, char**)::<lambda(auto:13&)> > >::_Iterator<false> >'
 1458 |    else if constexpr (derived_from<_Cat, forward_iterator_tag>)
      |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
d:/Programs/msys64/mingw64/include/c++/10.2.0/ranges:1459:34: error: inconsistent deduction for auto return type: 'std::bidirectional_iterator_tag' and then 'std::forward_iterator_tag'
 1459 |      return forward_iterator_tag{};
      |                                  ^

令我惊讶的是在加入的流上使用转换适配器没有任何问题。

我查看了范围的实现,但它只是提出了更多问题。范围的迭代器(上面的 r1...r4)具有iterator_conceptsiterator_category成员 typedef,但这些似乎不一致:

// r2) check member types directly
static_assert(std::is_same_v<typename decltype(r2.begin())::iterator_concept, std::random_access_iterator_tag>);
static_assert(std::is_same_v<typename decltype(r2.begin())::iterator_category, std::input_iterator_tag>);

// r2) check member types via iterator_traits
// why is it undefined?
// static_assert(std::is_same_v<typename std::iterator_traits<decltype(r2.begin())>::iterator_concept, ? >);
static_assert(std::is_same_v<typename std::iterator_traits<decltype(r2.begin())>::iterator_category, std::input_iterator_tag>);
                                                                                                                               
// r3) check member types directly
static_assert(std::is_same_v<typename decltype(r3.begin())::iterator_concept, std::input_iterator_tag>);                       
static_assert(std::is_same_v<typename decltype(r3.begin())::iterator_category, std::input_iterator_tag>);                      

// r3) check member types via iterator_traits
// why are these undefined?
// static_assert(std::is_same_v<typename std::iterator_traits<decltype(r3.begin())>::iterator_concept, ? >);
// static_assert(std::is_same_v<typename std::iterator_traits<decltype(r3.begin())>::iterator_category, ? >);

有没有办法让第 17 行的 for 循环工作?

4

0 回答 0