我在使用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_concepts
和iterator_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 循环工作?