如何将一对迭代器转换为视图?
How to convert a pair of iterator into a view?
我有一对迭代器,我想在其上使用 ranges::views::filter(some_predicate)
(使用管道运算符)。 AFAIU 我应该首先将我的迭代器对转换为视图。我尝试使用 ranges::subrange(first, last)
这样做,但我收到了可怕的错误消息。
注意 1:我使用的是 C++14 和 range-v3 版本 0.9.1(与 gcc-5.5 兼容的最新版本)。如果解决方案在使用 C++17/20 and/or 和使用 C++20 std::ranges 时有所不同,我也很想知道发生了什么变化。
注2:我找到了documentation of range-v3 severely lacking, so I’m using cppreference.com。如果你知道更好的文档,我很感兴趣。
编辑:
在我的真实代码中,我包装了一个 java 风格的遗留迭代器(它有一个 next()
方法而不是 operator++
/operator*
。我'我将它们包装在与 C++ 兼容的包装器中。然后我尝试将该包装器转换为视图,最后对其进行过滤。我在 godbolt 上重现了一个最小示例。这按照建议使用 iterator_range
,但它仍然没有编译(见下面的第二个编辑)。
#include "range/v3/all.hpp"
#include "range/v3/iterator_range.hpp"
class LegacyIteratorWrapper {
public:
using value_type = int;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
using iterator_category = std::input_iterator_tag;
// The type isn’t default-constructible, the error comes from here
LegacyIteratorWrapper() = delete;
static LegacyIteratorWrapper create();
reference operator*() const;
pointer operator->();
LegacyIteratorWrapper& operator++();
LegacyIteratorWrapper operator++(int);
friend bool operator==(const LegacyIteratorWrapper& a, const LegacyIteratorWrapper& b);
friend bool operator!=(const LegacyIteratorWrapper& a, const LegacyIteratorWrapper& b);
};
void foo()
{
LegacyIteratorWrapper begin { LegacyIteratorWrapper::create() };
LegacyIteratorWrapper end { LegacyIteratorWrapper::create() };
ranges::iterator_range<LegacyIteratorWrapper, LegacyIteratorWrapper> rng {begin, end};
auto _ = rng
| ranges::views::filter(
[&](auto _) { return true; }
)
;
}
In file included from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/functional/reference_wrapper.hpp:24:0,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/detail/variant.hpp:33,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/iterator/common_iterator.hpp:26,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/view/interface.hpp:24,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/view/ref.hpp:25,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/action/action.hpp:29,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/action.hpp:17,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/all.hpp:17,
from <source>:1:
/opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/functional/pipeable.hpp: In instantiation of 'constexpr auto ranges::operator|(Arg&&, Pipe) [with Arg = ranges::iterator_range<LegacyIteratorWrapper, LegacyIteratorWrapper>&; Pipe = ranges::views::view<ranges::make_pipeable_fn::operator()(Fun) const [with Fun = ranges::detail::bind_back_fn_<ranges::views::cpp20_filter_fn, foo()::<lambda(auto:15)> >]::_>; bool CPP_false_ = false; typename concepts::detail::identity<typename std::enable_if<(static_cast<bool>(((! is_pipeable_v<Arg>) && is_pipeable_v<Pipe>)) || CPP_false_), void>::type>::invoke<int> <anonymous> = 0]':
<source>:33:11: required from here
/opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/functional/pipeable.hpp:63:53: error: no matching function for call to 'ranges::pipeable_access::impl<ranges::views::view<ranges::make_pipeable_fn::operator()(Fun) const [with Fun = ranges::detail::bind_back_fn_<ranges::views::cpp20_filter_fn, foo()::<lambda(auto:15)> >]::_> >::pipe(ranges::iterator_range<LegacyIteratorWrapper, LegacyIteratorWrapper>&, ranges::views::view<ranges::make_pipeable_fn::operator()(Fun) const [with Fun = ranges::detail::bind_back_fn_<ranges::views::cpp20_filter_fn, foo()::<lambda(auto:15)> >]::_>&)'
return pipeable_access::impl<Pipe>::pipe(static_cast<Arg &&>(arg), pipe);
^
In file included from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/range_fwd.hpp:22:0,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/action/action.hpp:21,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/action.hpp:17,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/all.hpp:17,
from <source>:1:
/opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/view/view.hpp:114:35: note: candidate: template<class Rng, class Vw> static constexpr auto ranges::views::view<View>::pipe(Rng&&, Vw&&, concepts::detail::enable_if_t<concepts::detail::Nil, (static_cast<bool>((viewable_range<Rng> && invocable<View&, Rng>)) || concepts::detail::CPP_false(concepts::detail::Nil{}))>) [with Rng = Rng; Vw = Vw; View = ranges::make_pipeable_fn::operator()(Fun) const [with Fun = ranges::detail::bind_back_fn_<ranges::views::cpp20_filter_fn, foo()::<lambda(auto:15)> >]::_]
static constexpr auto CPP_fun(pipe)(Rng && rng, Vw && v)( //
^
/opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/view/view.hpp:114:35: note: template argument deduction/substitution failed:
<source>: In function 'void foo()':
<source>:33:11: error: 'void _' has incomplete type
)
^
ASM generation compiler returned: 1
In file included from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/functional/reference_wrapper.hpp:24:0,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/detail/variant.hpp:33,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/iterator/common_iterator.hpp:26,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/view/interface.hpp:24,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/view/ref.hpp:25,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/action/action.hpp:29,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/action.hpp:17,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/all.hpp:17,
from <source>:1:
/opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/functional/pipeable.hpp: In instantiation of 'constexpr auto ranges::operator|(Arg&&, Pipe) [with Arg = ranges::iterator_range<LegacyIteratorWrapper, LegacyIteratorWrapper>&; Pipe = ranges::views::view<ranges::make_pipeable_fn::operator()(Fun) const [with Fun = ranges::detail::bind_back_fn_<ranges::views::cpp20_filter_fn, foo()::<lambda(auto:15)> >]::_>; bool CPP_false_ = false; typename concepts::detail::identity<typename std::enable_if<(static_cast<bool>(((! is_pipeable_v<Arg>) && is_pipeable_v<Pipe>)) || CPP_false_), void>::type>::invoke<int> <anonymous> = 0]':
<source>:33:11: required from here
/opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/functional/pipeable.hpp:63:53: error: no matching function for call to 'ranges::pipeable_access::impl<ranges::views::view<ranges::make_pipeable_fn::operator()(Fun) const [with Fun = ranges::detail::bind_back_fn_<ranges::views::cpp20_filter_fn, foo()::<lambda(auto:15)> >]::_> >::pipe(ranges::iterator_range<LegacyIteratorWrapper, LegacyIteratorWrapper>&, ranges::views::view<ranges::make_pipeable_fn::operator()(Fun) const [with Fun = ranges::detail::bind_back_fn_<ranges::views::cpp20_filter_fn, foo()::<lambda(auto:15)> >]::_>&)'
return pipeable_access::impl<Pipe>::pipe(static_cast<Arg &&>(arg), pipe);
^
In file included from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/range_fwd.hpp:22:0,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/action/action.hpp:21,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/action.hpp:17,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/all.hpp:17,
from <source>:1:
/opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/view/view.hpp:114:35: note: candidate: template<class Rng, class Vw> static constexpr auto ranges::views::view<View>::pipe(Rng&&, Vw&&, concepts::detail::enable_if_t<concepts::detail::Nil, (static_cast<bool>((viewable_range<Rng> && invocable<View&, Rng>)) || concepts::detail::CPP_false(concepts::detail::Nil{}))>) [with Rng = Rng; Vw = Vw; View = ranges::make_pipeable_fn::operator()(Fun) const [with Fun = ranges::detail::bind_back_fn_<ranges::views::cpp20_filter_fn, foo()::<lambda(auto:15)> >]::_]
static constexpr auto CPP_fun(pipe)(Rng && rng, Vw && v)( //
^
/opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/view/view.hpp:114:35: note: template argument deduction/substitution failed:
<source>: In function 'void foo()':
<source>:33:11: error: 'void _' has incomplete type
)
^
Execution build compiler returned: 1
EDIT2(已解决):我得到一个错误,因为 LegacyIteratorWrapper
不是默认可构造的。这是满足常规特征(由 range-v3 模拟)所必需的,这是 C++ 迭代器所必需的,并且包括默认构造。
在 ranges-v3 中,iterator_range
可用于将迭代器包装到范围对象中。
在 C++20 中,您可以使用 std::span
将这些迭代器包装到范围对象中
I have a pair of iterator, and I would like to use ranges::views::filter(some_predicate)
on it (with the pipe operator). AFAIU I should first convert my pair of iterator into a view. I tried to use ranges::subrange(first, last)
to do so, but I’m getting horrible error messages.
由于您还没有真正提供代码来支持您的 收到可怕的错误消息,这里有一个在向量上定义两个迭代器的代码,使用 ranges::subrange
,并过滤结果范围。
#include <iostream>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/subrange.hpp>
#include <vector>
namespace r = ranges;
namespace rv = ranges::views;
int main() {
std::vector<int> v{1,2,3,4,5};
auto even = [](auto x){ return x % 2 == 0; };
auto i1 = v.begin() + 1;
auto ie = v.end() - 1;
auto w = r::subrange(i1, ie) | rv::filter(even);
for (auto i : w) {
std::cout << i << std::endl;
}
}
如果你澄清你的示例代码是什么以及你得到的错误是什么,我或其他人可以给你一个更好的答案。
您可以将每对相等的迭代器转换为 std::ranges::subrange
:
auto my_range = std::ranges::subrange{begi,endi};
我有一对迭代器,我想在其上使用 ranges::views::filter(some_predicate)
(使用管道运算符)。 AFAIU 我应该首先将我的迭代器对转换为视图。我尝试使用 ranges::subrange(first, last)
这样做,但我收到了可怕的错误消息。
注意 1:我使用的是 C++14 和 range-v3 版本 0.9.1(与 gcc-5.5 兼容的最新版本)。如果解决方案在使用 C++17/20 and/or 和使用 C++20 std::ranges 时有所不同,我也很想知道发生了什么变化。
注2:我找到了documentation of range-v3 severely lacking, so I’m using cppreference.com。如果你知道更好的文档,我很感兴趣。
编辑:
在我的真实代码中,我包装了一个 java 风格的遗留迭代器(它有一个 next()
方法而不是 operator++
/operator*
。我'我将它们包装在与 C++ 兼容的包装器中。然后我尝试将该包装器转换为视图,最后对其进行过滤。我在 godbolt 上重现了一个最小示例。这按照建议使用 iterator_range
,但它仍然没有编译(见下面的第二个编辑)。
#include "range/v3/all.hpp"
#include "range/v3/iterator_range.hpp"
class LegacyIteratorWrapper {
public:
using value_type = int;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
using iterator_category = std::input_iterator_tag;
// The type isn’t default-constructible, the error comes from here
LegacyIteratorWrapper() = delete;
static LegacyIteratorWrapper create();
reference operator*() const;
pointer operator->();
LegacyIteratorWrapper& operator++();
LegacyIteratorWrapper operator++(int);
friend bool operator==(const LegacyIteratorWrapper& a, const LegacyIteratorWrapper& b);
friend bool operator!=(const LegacyIteratorWrapper& a, const LegacyIteratorWrapper& b);
};
void foo()
{
LegacyIteratorWrapper begin { LegacyIteratorWrapper::create() };
LegacyIteratorWrapper end { LegacyIteratorWrapper::create() };
ranges::iterator_range<LegacyIteratorWrapper, LegacyIteratorWrapper> rng {begin, end};
auto _ = rng
| ranges::views::filter(
[&](auto _) { return true; }
)
;
}
In file included from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/functional/reference_wrapper.hpp:24:0,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/detail/variant.hpp:33,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/iterator/common_iterator.hpp:26,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/view/interface.hpp:24,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/view/ref.hpp:25,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/action/action.hpp:29,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/action.hpp:17,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/all.hpp:17,
from <source>:1:
/opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/functional/pipeable.hpp: In instantiation of 'constexpr auto ranges::operator|(Arg&&, Pipe) [with Arg = ranges::iterator_range<LegacyIteratorWrapper, LegacyIteratorWrapper>&; Pipe = ranges::views::view<ranges::make_pipeable_fn::operator()(Fun) const [with Fun = ranges::detail::bind_back_fn_<ranges::views::cpp20_filter_fn, foo()::<lambda(auto:15)> >]::_>; bool CPP_false_ = false; typename concepts::detail::identity<typename std::enable_if<(static_cast<bool>(((! is_pipeable_v<Arg>) && is_pipeable_v<Pipe>)) || CPP_false_), void>::type>::invoke<int> <anonymous> = 0]':
<source>:33:11: required from here
/opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/functional/pipeable.hpp:63:53: error: no matching function for call to 'ranges::pipeable_access::impl<ranges::views::view<ranges::make_pipeable_fn::operator()(Fun) const [with Fun = ranges::detail::bind_back_fn_<ranges::views::cpp20_filter_fn, foo()::<lambda(auto:15)> >]::_> >::pipe(ranges::iterator_range<LegacyIteratorWrapper, LegacyIteratorWrapper>&, ranges::views::view<ranges::make_pipeable_fn::operator()(Fun) const [with Fun = ranges::detail::bind_back_fn_<ranges::views::cpp20_filter_fn, foo()::<lambda(auto:15)> >]::_>&)'
return pipeable_access::impl<Pipe>::pipe(static_cast<Arg &&>(arg), pipe);
^
In file included from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/range_fwd.hpp:22:0,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/action/action.hpp:21,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/action.hpp:17,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/all.hpp:17,
from <source>:1:
/opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/view/view.hpp:114:35: note: candidate: template<class Rng, class Vw> static constexpr auto ranges::views::view<View>::pipe(Rng&&, Vw&&, concepts::detail::enable_if_t<concepts::detail::Nil, (static_cast<bool>((viewable_range<Rng> && invocable<View&, Rng>)) || concepts::detail::CPP_false(concepts::detail::Nil{}))>) [with Rng = Rng; Vw = Vw; View = ranges::make_pipeable_fn::operator()(Fun) const [with Fun = ranges::detail::bind_back_fn_<ranges::views::cpp20_filter_fn, foo()::<lambda(auto:15)> >]::_]
static constexpr auto CPP_fun(pipe)(Rng && rng, Vw && v)( //
^
/opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/view/view.hpp:114:35: note: template argument deduction/substitution failed:
<source>: In function 'void foo()':
<source>:33:11: error: 'void _' has incomplete type
)
^
ASM generation compiler returned: 1
In file included from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/functional/reference_wrapper.hpp:24:0,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/detail/variant.hpp:33,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/iterator/common_iterator.hpp:26,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/view/interface.hpp:24,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/view/ref.hpp:25,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/action/action.hpp:29,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/action.hpp:17,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/all.hpp:17,
from <source>:1:
/opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/functional/pipeable.hpp: In instantiation of 'constexpr auto ranges::operator|(Arg&&, Pipe) [with Arg = ranges::iterator_range<LegacyIteratorWrapper, LegacyIteratorWrapper>&; Pipe = ranges::views::view<ranges::make_pipeable_fn::operator()(Fun) const [with Fun = ranges::detail::bind_back_fn_<ranges::views::cpp20_filter_fn, foo()::<lambda(auto:15)> >]::_>; bool CPP_false_ = false; typename concepts::detail::identity<typename std::enable_if<(static_cast<bool>(((! is_pipeable_v<Arg>) && is_pipeable_v<Pipe>)) || CPP_false_), void>::type>::invoke<int> <anonymous> = 0]':
<source>:33:11: required from here
/opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/functional/pipeable.hpp:63:53: error: no matching function for call to 'ranges::pipeable_access::impl<ranges::views::view<ranges::make_pipeable_fn::operator()(Fun) const [with Fun = ranges::detail::bind_back_fn_<ranges::views::cpp20_filter_fn, foo()::<lambda(auto:15)> >]::_> >::pipe(ranges::iterator_range<LegacyIteratorWrapper, LegacyIteratorWrapper>&, ranges::views::view<ranges::make_pipeable_fn::operator()(Fun) const [with Fun = ranges::detail::bind_back_fn_<ranges::views::cpp20_filter_fn, foo()::<lambda(auto:15)> >]::_>&)'
return pipeable_access::impl<Pipe>::pipe(static_cast<Arg &&>(arg), pipe);
^
In file included from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/range_fwd.hpp:22:0,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/action/action.hpp:21,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/action.hpp:17,
from /opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/all.hpp:17,
from <source>:1:
/opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/view/view.hpp:114:35: note: candidate: template<class Rng, class Vw> static constexpr auto ranges::views::view<View>::pipe(Rng&&, Vw&&, concepts::detail::enable_if_t<concepts::detail::Nil, (static_cast<bool>((viewable_range<Rng> && invocable<View&, Rng>)) || concepts::detail::CPP_false(concepts::detail::Nil{}))>) [with Rng = Rng; Vw = Vw; View = ranges::make_pipeable_fn::operator()(Fun) const [with Fun = ranges::detail::bind_back_fn_<ranges::views::cpp20_filter_fn, foo()::<lambda(auto:15)> >]::_]
static constexpr auto CPP_fun(pipe)(Rng && rng, Vw && v)( //
^
/opt/compiler-explorer/libs/rangesv3/0.9.1/include/range/v3/view/view.hpp:114:35: note: template argument deduction/substitution failed:
<source>: In function 'void foo()':
<source>:33:11: error: 'void _' has incomplete type
)
^
Execution build compiler returned: 1
EDIT2(已解决):我得到一个错误,因为 LegacyIteratorWrapper
不是默认可构造的。这是满足常规特征(由 range-v3 模拟)所必需的,这是 C++ 迭代器所必需的,并且包括默认构造。
在 ranges-v3 中,iterator_range
可用于将迭代器包装到范围对象中。
在 C++20 中,您可以使用 std::span
将这些迭代器包装到范围对象中
I have a pair of iterator, and I would like to use
ranges::views::filter(some_predicate)
on it (with the pipe operator). AFAIU I should first convert my pair of iterator into a view. I tried to useranges::subrange(first, last)
to do so, but I’m getting horrible error messages.
由于您还没有真正提供代码来支持您的 收到可怕的错误消息,这里有一个在向量上定义两个迭代器的代码,使用 ranges::subrange
,并过滤结果范围。
#include <iostream>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/subrange.hpp>
#include <vector>
namespace r = ranges;
namespace rv = ranges::views;
int main() {
std::vector<int> v{1,2,3,4,5};
auto even = [](auto x){ return x % 2 == 0; };
auto i1 = v.begin() + 1;
auto ie = v.end() - 1;
auto w = r::subrange(i1, ie) | rv::filter(even);
for (auto i : w) {
std::cout << i << std::endl;
}
}
如果你澄清你的示例代码是什么以及你得到的错误是什么,我或其他人可以给你一个更好的答案。
您可以将每对相等的迭代器转换为 std::ranges::subrange
:
auto my_range = std::ranges::subrange{begi,endi};