为什么它是在 std::ranges 中完成的,我无法分割从 join 和转换中获得的范围
为什么这段代码不编译,如何修复它,同时仍然使用 std::ranges 的声明性方法,而不是在转换后创建中间非惰性容器作为 std::vector ?
auto Foo(std::vector<std::string_view> viewsVec) -> void {
std::println("{}",
viewsVec | std::views::transform([](std::string_view str) -> std::string_view {
return str.substr(1);
}) | std::views::join |
std::views::split('\n'));
}
我收到以下编译错误: clang++ -std=c++23 split.cpp
split.cpp:10:38: error: invalid operands to binary expression ('invoke_result_t<const __fn &, transform_view<ref_view<vector<string_view,
allocator<string_view>>>, (lambda at split.cpp:8:49)>>' (aka
'std::ranges::join_view<std::ranges::transform_view<std::ranges::ref_view<std::vector<std::string_view>>, (lambda at split.cpp:8:49)>>') and
'__range_adaptor_closure_t<__bind_back_t<__fn, tuple<char>>>' (aka
'std::ranges::__range_adaptor_closure_t<std::__bind_back_t<std::ranges::views::__split_view::__fn, std::tuple<char>>>'))
8 | viewsVec | std::views::transform([](std::string_view str) -> std::string_view {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 | return str.substr(1);
| ~~~~~~~~~~~~~~~~~~~~~
10 | }) | std::views::join |
| ~~~~~~~~~~~~~~~~~~~~~ ^
11 | std::views::split('\n'));
| ~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/v1/cstddef:73:45: note: candidate function not viable: no known conversion from 'invoke_result_t<const __fn &,
transform_view<ref_view<vector<string_view, allocator<string_view>>>, (lambda at split.cpp:8:49)>>' (aka
'std::ranges::join_view<std::ranges::transform_view<std::ranges::ref_view<std::vector<std::string_view>>, (lambda at split.cpp:8:49)>>') to 'byte' for 1st
argument
73 | _LIBCPP_HIDE_FROM_ABI inline constexpr byte operator|(byte __lhs, byte __rhs) noexcept {
| ^ ~~~~~~~~~~
/usr/include/c++/v1/__charconv/chars_format.h:34:53: note: candidate function not viable: no known conversion from 'invoke_result_t<const __fn &,
transform_view<ref_view<vector<string_view, allocator<string_view>>>, (lambda at split.cpp:8:49)>>' (aka
'std::ranges::join_view<std::ranges::transform_view<std::ranges::ref_view<std::vector<std::string_view>>, (lambda at split.cpp:8:49)>>') to 'chars_format' for
1st argument
34 | inline _LIBCPP_HIDE_FROM_ABI constexpr chars_format operator|(chars_format __x, chars_format __y) {
| ^ ~~~~~~~~~~~~~~~~
/usr/include/c++/v1/__ranges/range_adaptor.h:71:1: note: candidate template ignored: constraints not satisfied [with _Range =
invoke_result_t<const __fn &, transform_view<ref_view<vector<string_view, allocator<string_view>>>, (lambda at split.cpp:8:49)>>, _Closure =
__range_adaptor_closure_t<__bind_back_t<__fn, tuple<char>>>]
71 | operator|(_Range&& __range, _Closure&& __closure) noexcept(is_nothrow_invocable_v<_Closure, _Range>) {
| ^
/usr/include/c++/v1/__ranges/range_adaptor.h:69:12: note: because
'invocable<std::ranges::__range_adaptor_closure_t<std::__bind_back_t<std::ranges::views::__split_view::__fn, std::tuple<char> > >,
std::ranges::join_view<std::ranges::transform_view<std::ranges::ref_view<std::vector<std::string_view> >, (lambda at split.cpp:8:49)> > >' evaluated to false
69 | requires invocable<_Closure, _Range>
| ^
/usr/include/c++/v1/__concepts/invocable.h:28:3: note: because 'std::invoke(std::forward<_Fn>(__fn), std::forward<_Args>(__args)...)' would be
invalid: no matching function for call to 'invoke'
28 | std::invoke(std::forward<_Fn>(__fn), std::forward<_Args>(__args)...); // not required to be equality preserving
| ^
/usr/include/c++/v1/__ranges/range_adaptor.h:77:52: note: candidate template ignored: constraints not satisfied [with _Closure =
invoke_result_t<const __fn &, transform_view<ref_view<vector<string_view, allocator<string_view>>>, (lambda at split.cpp:8:49)>>, _OtherClosure =
__range_adaptor_closure_t<__bind_back_t<__fn, tuple<char>>>]
77 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator|(_Closure&& __c1, _OtherClosure&& __c2) noexcept(
| ^
/usr/include/c++/v1/__ranges/range_adaptor.h:75:11: note: because
'std::ranges::join_view<std::ranges::transform_view<std::ranges::ref_view<std::vector<std::string_view>>, (lambda at split.cpp:8:49)>>' does not satisfy
'_RangeAdaptorClosure'
75 | template <_RangeAdaptorClosure _Closure, _RangeAdaptorClosure _OtherClosure>
| ^
/usr/include/c++/v1/__ranges/range_adaptor.h:62:32: note: because
'!ranges::range<remove_cvref_t<join_view<transform_view<ref_view<vector<string_view, allocator<string_view> > >, (lambda at split.cpp:8:49)> > > >' evaluated to
false
62 | concept _RangeAdaptorClosure = !ranges::range<remove_cvref_t<_Tp>> && requires {
| ^
1 error generated.
clang --版本:
clang version 19.1.0+libcxx
Target: x86_64-pc-linux-musl
Thread model: posix
InstalledDir: /usr/lib/llvm/19/bin
Configuration file: /etc/clang/x86_64-pc-linux-musl-clang.cfg
稍微重新格式化您的代码并删除不相关的
println
:
auto Foo(std::vector<std::string_view> viewsVec) -> void {
auto f = viewsVec // (1)
| std::views::transform([](std::string_view str) -> std::string_view {
return str.substr(1);
}) // (2)
| std::views::join // (3)
| std::views::split('\n'); // (4)
}
我们可以注释我们的步骤:
viewsVec
是 string_view
transform
是string_view
join
是 char
的输入
views::split
需要前进或更好。join
范围的纯右值范围必须是input
范围,因为每个范围都必须存储在某个地方 - 必须位于join_view
本身内。一旦你缓存了,你就只能是输入了。
然后
split
需要前向,以便提供方便的行为并成为 subrange
的范围 - 只有当您实际上可以在范围中包含多个迭代器时,这才有可能。
为此,您需要
views::lazy_split
— 这是一个不太方便的范围适配器,但适用于输入范围。