c++ - 如何使用 C++20 istream_view?

标签 c++ c++20 std-ranges

我在网络或 C++20 书籍中找不到一个示例来说明如何将 std::ranges::istream_view 的结果用于后续操作。我尝试使用的每个后续操作都会导致编译器错误,而这些错误对我来说很难单独解决。

例如,我应该如何拆分通过 istream_view 传入的惰性字符流?以下代码不起作用,但希望能够传达我想要实现的目标:

#include <cstdlib>
#include <ranges>
#include <sstream>
#include <fmt/core.h>

auto main() -> int
{
  std::istringstream data{"a,b"};
  for (const auto& item:
      std::views::istream<std::string>(data)
    | std::views::split(",")
  ) {
    fmt::print("{}\n", item);
  }
  return EXIT_SUCCESS;
}

^ 我希望在第一行写入 "a",在第二行写入 "b"

GCC 12.2 发出一条令人生畏的错误消息:

Could not execute the program
Compiler returned: 1
Compiler stderr
<source>: In function 'int main()':
<source>:11:5: error: no match for 'operator|' (operand types are 'std::ranges::basic_istream_view<std::__cxx11::basic_string<char>, char, std::char_traits<char> >' and 'std::ranges::views::__adaptor::_Partial<std::ranges::views::_Split, const char*>')
   10 |       std::views::istream<std::string>(data)
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                       |
      |                                       std::ranges::basic_istream_view<std::__cxx11::basic_string<char>, char, std::char_traits<char> >
   11 |     | std::views::split(",")
      |     ^ ~~~~~~~~~~~~~~~~~~~~~~
      |                        |
      |                        std::ranges::views::__adaptor::_Partial<std::ranges::views::_Split, const char*>
In file included from <source>:2:
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/ranges:868:7: note: candidate: 'template<class _Lhs, class _Rhs>  requires (derived_from<_Lhs, std::ranges::views::__adaptor::_RangeAdaptorClosure>) && (derived_from<_Rhs, std::ranges::views::__adaptor::_RangeAdaptorClosure>) constexpr auto std::ranges::views::__adaptor::operator|(_Lhs, _Rhs)'
  868 |       operator|(_Lhs __lhs, _Rhs __rhs)
      |       ^~~~~~~~
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/ranges:868:7: note:   template argument deduction/substitution failed:
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/ranges:868:7: note: constraints not satisfied
In file included from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/ranges:37:
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/concepts: In substitution of 'template<class _Lhs, class _Rhs>  requires (derived_from<_Lhs, std::ranges::views::__adaptor::_RangeAdaptorClosure>) && (derived_from<_Rhs, std::ranges::views::__adaptor::_RangeAdaptorClosure>) constexpr auto std::ranges::views::__adaptor::operator|(_Lhs, _Rhs) [with _Lhs = std::ranges::basic_istream_view<std::__cxx11::basic_string<char>, char, std::char_traits<char> >; _Rhs = std::ranges::views::__adaptor::_Partial<std::ranges::views::_Split, const char*>]':
<source>:11:28:   required from here
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/concepts:67:13:   required for the satisfaction of 'derived_from<_Lhs, std::ranges::views::__adaptor::_RangeAdaptorClosure>' [with _Lhs = std::ranges::basic_istream_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, char, std::char_traits<char> >]
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/concepts:67:28: note:   'std::ranges::views::__adaptor::_RangeAdaptorClosure' is not a base of 'std::ranges::basic_istream_view<std::__cxx11::basic_string<char>, char, std::char_traits<char> >'
   67 |     concept derived_from = __is_base_of(_Base, _Derived)
      |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/ranges:859:7: note: candidate: 'template<class _Self, class _Range>  requires (derived_from<typename std::remove_cvref<_Tp>::type, std::ranges::views::__adaptor::_RangeAdaptorClosure>) && (__adaptor_invocable<_Self, _Range>) constexpr auto std::ranges::views::__adaptor::operator|(_Range&&, _Self&&)'
  859 |       operator|(_Range&& __r, _Self&& __self)
      |       ^~~~~~~~
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/ranges:859:7: note:   template argument deduction/substitution failed:
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/ranges:859:7: note: constraints not satisfied
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/ranges: In substitution of 'template<class _Self, class _Range>  requires (derived_from<typename std::remove_cvref<_Tp>::type, std::ranges::views::__adaptor::_RangeAdaptorClosure>) && (__adaptor_invocable<_Self, _Range>) constexpr auto std::ranges::views::__adaptor::operator|(_Range&&, _Self&&) [with _Self = std::ranges::views::__adaptor::_Partial<std::ranges::views::_Split, const char*>; _Range = std::ranges::basic_istream_view<std::__cxx11::basic_string<char>, char, std::char_traits<char> >]':
<source>:11:28:   required from here
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/ranges:831:13:   required for the satisfaction of '__adaptor_invocable<_Self, _Range>' [with _Self = std::ranges::views::__adaptor::_Partial<std::ranges::views::_Split, const char*>; _Range = std::ranges::basic_istream_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, char, std::char_traits<char> >]
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/ranges:832:9:   in requirements  [with _Args = {std::ranges::basic_istream_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, char, std::char_traits<char> >}; _Adaptor = std::ranges::views::__adaptor::_Partial<std::ranges::views::_Split, const char*>]
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/ranges:832:44: note: the required expression 'declval<_Adaptor>()((declval<_Args>)()...)' is invalid
  832 |       = requires { std::declval<_Adaptor>()(declval<_Args>()...); };
      |                    ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
cc1plus: note: set '-fconcepts-diagnostics-depth=' to at least 2 for more detail
In file included from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/streambuf:41,
                 from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/streambuf_iterator.h:35,
                 from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/iterator:66,
                 from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/ranges:43:
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/ios_base.h:87:3: note: candidate: 'constexpr std::_Ios_Fmtflags std::operator|(_Ios_Fmtflags, _Ios_Fmtflags)'
   87 |   operator|(_Ios_Fmtflags __a, _Ios_Fmtflags __b)
      |   ^~~~~~~~
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/ios_base.h:87:27: note:   no known conversion for argument 1 from 'std::ranges::basic_istream_view<std::__cxx11::basic_string<char>, char, std::char_traits<char> >' to 'std::_Ios_Fmtflags'
   87 |   operator|(_Ios_Fmtflags __a, _Ios_Fmtflags __b)
      |             ~~~~~~~~~~~~~~^~~
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/ios_base.h:130:3: note: candidate: 'constexpr std::_Ios_Openmode std::operator|(_Ios_Openmode, _Ios_Openmode)'
  130 |   operator|(_Ios_Openmode __a, _Ios_Openmode __b)
      |   ^~~~~~~~
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/ios_base.h:130:27: note:   no known conversion for argument 1 from 'std::ranges::basic_istream_view<std::__cxx11::basic_string<char>, char, std::char_traits<char> >' to 'std::_Ios_Openmode'
  130 |   operator|(_Ios_Openmode __a, _Ios_Openmode __b)
      |             ~~~~~~~~~~~~~~^~~
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/ios_base.h:170:3: note: candidate: 'constexpr std::_Ios_Iostate std::operator|(_Ios_Iostate, _Ios_Iostate)'
  170 |   operator|(_Ios_Iostate __a, _Ios_Iostate __b)
      |   ^~~~~~~~
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/ios_base.h:170:26: note:   no known conversion for argument 1 from 'std::ranges::basic_istream_view<std::__cxx11::basic_string<char>, char, std::char_traits<char> >' to 'std::_Ios_Iostate'
  170 |   operator|(_Ios_Iostate __a, _Ios_Iostate __b)
      |             ~~~~~~~~~~~~~^~~
In file included from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/span:42,
                 from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/ranges:45:
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/cstddef:132:3: note: candidate: 'constexpr std::byte std::operator|(byte, byte)'
  132 |   operator|(byte __l, byte __r) noexcept
      |   ^~~~~~~~
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/cstddef:132:18: note:   no known conversion for argument 1 from 'std::ranges::basic_istream_view<std::__cxx11::basic_string<char>, char, std::char_traits<char> >' to 'std::byte'
  132 |   operator|(byte __l, byte __r) noexcept
      |             ~~~~~^~~

最佳答案

views::istream是一个输入范围。因此,您通过管道连接到的任何适配器都必须在输入范围内工作。 views::split需要向前或更好,这就是为什么你不能 split一个istream .

但是还有一个views::lazy_split它提供了一个稍微不同的接口(interface),使其确实适用于输入范围(请参阅 P2210 以了解为什么我们需要forward+ split 适配器的附加上下文)。

但是,那么您就会遇到 views::istream<string> 的问题范围为 string您正在尝试用逗号分隔。但这不太正确,你想要的是 char 的范围。这样你最终得到的范围是 char 。你的意思是views::istream<char> .

解决这个问题,this works :

auto main() -> int
{
  std::istringstream data{"a,b"};
  fmt::print("{}\n",
      std::views::istream<char>(data)
    | std::views::lazy_split(','));
}

打印 [['a'], ['b']]

关于c++ - 如何使用 C++20 istream_view?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74647598/

相关文章:

c++ - clang-tidy(版本 14)是否正确,此代码上有 `bugprone-use-after-move` 错误?

c++ - 使用范围拆分 string_view

c++ - 为什么我不能使用 istream_view 和 std::accumulate 来总结我的输入?

c++ - 在哪种情况下我们应该更喜欢返回错误值而不是抛出异常

c++ - 编译用于高放射性环境的应用程序

c++ - CUDA 代码中的模板使用

c++ - 考虑到无限的 iota 并不是一个大小范围

c++ - 如果我不给它提供命令行参数,为什么我的程序会崩溃?

C++ 飞船运算符多级比较?

C++ 为什么受约束的算法(例如 std::ranges::merge)也返回输入范围的结尾?