为什么它是在 std::ranges 中完成的,我无法分割通过变换连接得到的范围

问题描述 投票:0回答:1

为什么它是在 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
c++ functional-programming std-ranges c++23
1个回答
0
投票

稍微重新格式化您的代码并删除不相关的

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)
}

我们可以注释我们的步骤:

  1. viewsVec
    string_view
  2. 的连续范围
  3. transform
    string_view
  4. 的随机访问范围
  5. join
    char
    输入
  6. 范围
  7. 这意味着这不起作用,因为
    views::split
    需要前进或更好。

join
范围的纯右值范围必须是
input
范围,因为每个范围都必须存储在某个地方 - 必须位于
join_view
本身内。一旦你缓存了,你就只能是输入了。

然后

split
需要前向,以便提供方便的行为并成为
subrange
的范围 - 只有当您实际上可以在范围中包含多个迭代器时,这才有可能。

为此,您需要

views::lazy_split
— 这是一个不太方便的范围适配器,但适用于输入范围。

© www.soinside.com 2019 - 2024. All rights reserved.