【问题标题】:Joining a range of strings with a delimiter using standard ranges使用标准范围将字符串范围与分隔符连接起来
【发布时间】:2020-08-28 15:55:46
【问题描述】:

我想使用范围将跨度中包含的四个字节转换为字符串。下面是一个输入输出的例子:

std::span<std::byte> data{bytes}; // contains 0x11, 0x22, 0x33, 0x44

std::string result = ...; // results in 44:33:22:11

这是我想出的,遵循range-v3 how to action::join with delimiter 的答案:

auto const result = data
    | views::reverse
    | views::transform([](std::byte byte) { return fmt::format("{:02x}", byte); })
    | views::join(':');

但是,它无法编译并出现非常...让我们说详细的错误:

 file.cpp: In function 'my_function {anonymous}::decode_function(std::span<const std::byte>)':
 file.cpp:87:21: error: no match for call to '(const std::ranges::views::__adaptor::_RangeAdaptorClosure<std::ranges::views::<lambda(_Range&&)> >) (char)'
    87 |    | views::join(':');
       |                     ^
 In file included from file.cpp:3:
 /usr/include/c++/10/ranges:1157:4: note: candidate: 'constexpr auto std::ranges::views::__adaptor::_RangeAdaptorClosure<_Callable>::operator()(_Range&&) const [with _Range = char; _Callable = std::ranges::views::<lambda(_Range&&)>]'
  1157 |    operator()(_Range&& __r) const
       |    ^~~~~~~~
 /usr/include/c++/10/ranges:1157:4: note: constraints not satisfied
 In file included from /usr/include/c++/10/string_view:44,
                  from file.h:4,
                  from file.cpp:1:
 /usr/include/c++/10/bits/range_access.h: In instantiation of 'constexpr auto std::ranges::views::__adaptor::_RangeAdaptorClosure<_Callable>::operator()(_Range&&) const [with _Range = char; _Callable = std::ranges::views::<lambda(_Range&&)>]':
 file.cpp:87:21:   required from here
 /usr/include/c++/10/bits/range_access.h:861:13:   required for the satisfaction of 'range<_Tp>' [with _Tp = char]
 /usr/include/c++/10/ranges:78:13:   required for the satisfaction of 'viewable_range<_Range>' [with _Range = char]
 /usr/include/c++/10/bits/range_access.h:861:21:   in requirements with 'char& __t'
 /usr/include/c++/10/bits/range_access.h:863:15: note: the required expression 'std::ranges::__cust::begin(__t)' is invalid, because
   863 |  ranges::begin(__t);
       |  ~~~~~~~~~~~~~^~~~~
 /usr/include/c++/10/bits/range_access.h:863:15: error: no match for call to '(const std::ranges::__cust_access::_Begin) (char&)'
 /usr/include/c++/10/bits/range_access.h:399:2: note: candidate: 'constexpr auto std::ranges::__cust_access::_Begin::operator()(_Tp&&) const [with _Tp = char&]'
   399 |  operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp>())
       |  ^~~~~~~~
 /usr/include/c++/10/bits/range_access.h:399:2: note: constraints not satisfied
 /usr/include/c++/10/bits/range_access.h: In instantiation of 'constexpr auto std::ranges::__cust_access::_Begin::operator()(_Tp&&) const [with _Tp = char&]':
 /usr/include/c++/10/bits/range_access.h:863:15:   required from 'constexpr auto std::ranges::views::__adaptor::_RangeAdaptorClosure<_Callable>::operator()(_Range&&) const [with _Range = char; _Callable = std::ranges::views::<lambda(_Range&&)>]'
 file.cpp:87:21:   required from here
 /usr/include/c++/10/bits/range_access.h:399:2:   required by the constraints of 'template<class _Tp>  requires (__maybe_borrowed_range<_Tp>) && ((is_array_v<typename std::remove_reference<_Tp>::type>) || (__member_begin<_Tp>) || (__adl_begin<_Tp>)) constexpr auto std::ranges::__cust_access::_Begin::operator()(_Tp&&) const'
 /usr/include/c++/10/bits/range_access.h:397:4: note: no operand of the disjunction is satisfied
   396 |  requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
       |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   397 |    || __adl_begin<_Tp>
       |    ^~~~~~~~~~~~~~~~~~~
 /usr/include/c++/10/bits/range_access.h:396:11: note: the operand 'is_array_v<std::remove_reference_t<_Tp> >' is unsatisfied because
   396 |  requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
       |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   397 |    || __adl_begin<_Tp>
       |    ~~~~~~~~~~~~~~~~~~~
 /usr/include/c++/10/bits/range_access.h:399:2:   required by the constraints of 'template<class _Tp>  requires (__maybe_borrowed_range<_Tp>) && ((is_array_v<typename std::remove_reference<_Tp>::type>) || (__member_begin<_Tp>) || (__adl_begin<_Tp>)) constexpr auto std::ranges::__cust_access::_Begin::operator()(_Tp&&) const'
 /usr/include/c++/10/bits/range_access.h:396:11: note: the expression 'is_array_v<typename std::remove_reference<_Tp>::type> [with _Tp = char&; _Tp = char&]' evaluated to 'false'
   396 |  requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
       |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 /usr/include/c++/10/bits/range_access.h:396:50: note: the operand '__member_begin<_Tp>' is unsatisfied because
   396 |  requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
       |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
   397 |    || __adl_begin<_Tp>
       |    ~~~~~~~~~~~~~~~~~~~                            
 In file included from /usr/include/c++/10/bits/stl_iterator_base_types.h:71,
                  from /usr/include/c++/10/bits/stl_algobase.h:65,
                  from /usr/include/c++/10/bits/char_traits.h:39,
                  from /usr/include/c++/10/string_view:41,
                  from file.h:4,
                  from file.cpp:1:
 /usr/include/c++/10/bits/iterator_concepts.h:847:15:   required for the satisfaction of '__member_begin<_Tp>' [with _Tp = char&]
 /usr/include/c++/10/bits/iterator_concepts.h:847:32:   in requirements with 'char& __t'
 /usr/include/c++/10/bits/iterator_concepts.h:849:28: note: the required expression 'std::__detail::__decay_copy(__t.begin())' is invalid, because
   849 |    { __detail::__decay_copy(__t.begin()) } -> input_or_output_iterator;
       |      ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
 /usr/include/c++/10/bits/iterator_concepts.h:849:33: error: request for member 'begin' in '__t', which is of non-class type 'char'
   849 |    { __detail::__decay_copy(__t.begin()) } -> input_or_output_iterator;
       |                             ~~~~^~~~~
 In file included from /usr/include/c++/10/string_view:44,
                  from file.h:4,
                  from file.cpp:1:
 /usr/include/c++/10/bits/range_access.h:397:7: note: the operand '__adl_begin<_Tp>' is unsatisfied because
   396 |  requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
       |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   397 |    || __adl_begin<_Tp>
       |    ~~~^~~~~~~~~~~~~~~~
 In file included from /usr/include/c++/10/compare:39,
                  from /usr/include/c++/10/bits/stl_pair.h:65,
                  from /usr/include/c++/10/bits/stl_algobase.h:64,
                  from /usr/include/c++/10/bits/char_traits.h:39,
                  from /usr/include/c++/10/string_view:41,
                  from file.h:4,
                  from file.cpp:1:
 /usr/include/c++/10/concepts:119:10:   required for the satisfaction of '__class_or_enum<typename std::remove_reference<_Tp>::type>' [with _Tp = char&]
 /usr/include/c++/10/bits/iterator_concepts.h:856:15:   required for the satisfaction of '__adl_begin<_Tp>' [with _Tp = char&]
 /usr/include/c++/10/concepts:120:41: note: no operand of the disjunction is satisfied
   120 |    = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
       |      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~
 /usr/include/c++/10/concepts:120:6: note: the operand 'is_class_v<_Tp>' is unsatisfied because
   120 |    = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
       |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 /usr/include/c++/10/concepts:119:10:   required for the satisfaction of '__class_or_enum<typename std::remove_reference<_Tp>::type>' [with _Tp = char&]
 /usr/include/c++/10/bits/iterator_concepts.h:856:15:   required for the satisfaction of '__adl_begin<_Tp>' [with _Tp = char&]
 /usr/include/c++/10/concepts:120:6: note: the expression 'is_class_v<_Tp> [with _Tp = char]' evaluated to 'false'
   120 |    = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
       |      ^~~~~~~~~~~~~~~
 /usr/include/c++/10/concepts:120:25: note: the operand 'is_union_v<_Tp>' is unsatisfied because
   120 |    = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
       |      ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 /usr/include/c++/10/concepts:119:10:   required for the satisfaction of '__class_or_enum<typename std::remove_reference<_Tp>::type>' [with _Tp = char&]
 /usr/include/c++/10/bits/iterator_concepts.h:856:15:   required for the satisfaction of '__adl_begin<_Tp>' [with _Tp = char&]
 /usr/include/c++/10/concepts:120:25: note: the expression 'is_union_v<_Tp> [with _Tp = char]' evaluated to 'false'
   120 |    = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
       |                         ^~~~~~~~~~~~~~~
 /usr/include/c++/10/concepts:120:44: note: the operand 'is_enum_v<_Tp>' is unsatisfied because
   120 |    = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
       |      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~
 /usr/include/c++/10/concepts:119:10:   required for the satisfaction of '__class_or_enum<typename std::remove_reference<_Tp>::type>' [with _Tp = char&]
 /usr/include/c++/10/bits/iterator_concepts.h:856:15:   required for the satisfaction of '__adl_begin<_Tp>' [with _Tp = char&]
 /usr/include/c++/10/concepts:120:44: note: the expression 'is_enum_v<_Tp> [with _Tp = char]' evaluated to 'false'
   120 |    = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
       |                                            ^~~~~~~~~~~~~~
 In file included from /usr/include/c++/10/string_view:44,
                  from file.h:4,
                  from file.cpp:1:
 /usr/include/c++/10/bits/range_access.h: In instantiation of 'constexpr auto std::ranges::views::__adaptor::_RangeAdaptorClosure<_Callable>::operator()(_Range&&) const [with _Range = char; _Callable = std::ranges::views::<lambda(_Range&&)>]':
 file.cpp:87:21:   required from here
 /usr/include/c++/10/bits/range_access.h:864:13: note: the required expression 'std::ranges::__cust::end(__t)' is invalid, because
   864 |  ranges::end(__t);
       |  ~~~~~~~~~~~^~~~~
 /usr/include/c++/10/bits/range_access.h:864:13: error: no match for call to '(const std::ranges::__cust_access::_End) (char&)'
 /usr/include/c++/10/bits/range_access.h:453:2: note: candidate: 'constexpr auto std::ranges::__cust_access::_End::operator()(_Tp&&) const [with _Tp = char&]'
   453 |  operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp>())
       |  ^~~~~~~~
 /usr/include/c++/10/bits/range_access.h:453:2: note: constraints not satisfied
 /usr/include/c++/10/bits/range_access.h: In instantiation of 'constexpr auto std::ranges::__cust_access::_End::operator()(_Tp&&) const [with _Tp = char&]':
 /usr/include/c++/10/bits/range_access.h:864:13:   required from 'constexpr auto std::ranges::views::__adaptor::_RangeAdaptorClosure<_Callable>::operator()(_Range&&) const [with _Range = char; _Callable = std::ranges::views::<lambda(_Range&&)>]'
 file.cpp:87:21:   required from here
 /usr/include/c++/10/bits/range_access.h:453:2:   required by the constraints of 'template<class _Tp>  requires (__maybe_borrowed_range<_Tp>) && ((is_bounded_array_v<typename std::remove_reference<_Tp>::type>) || (__member_end<_Tp>) || (__adl_end<_Tp>)) constexpr auto std::ranges::__cust_access::_End::operator()(_Tp&&) const'
 /usr/include/c++/10/bits/range_access.h:451:2: note: no operand of the disjunction is satisfied
   450 |  requires is_bounded_array_v<remove_reference_t<_Tp>> || __member_end<_Tp>
       |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   451 |  || __adl_end<_Tp>
       |  ^~~~~~~~~~~~~~~~~
 /usr/include/c++/10/bits/range_access.h:450:11: note: the operand 'is_bounded_array_v<std::remove_reference_t<_Tp> >' is unsatisfied because
   450 |  requires is_bounded_array_v<remove_reference_t<_Tp>> || __member_end<_Tp>
       |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   451 |  || __adl_end<_Tp>
       |  ~~~~~~~~~~~~~~~~~
 /usr/include/c++/10/bits/range_access.h:453:2:   required by the constraints of 'template<class _Tp>  requires (__maybe_borrowed_range<_Tp>) && ((is_bounded_array_v<typename std::remove_reference<_Tp>::type>) || (__member_end<_Tp>) || (__adl_end<_Tp>)) constexpr auto std::ranges::__cust_access::_End::operator()(_Tp&&) const'
 /usr/include/c++/10/bits/range_access.h:450:11: note: the expression 'is_bounded_array_v<typename std::remove_reference<_Tp>::type> [with _Tp = char&; _Tp = char&]' evaluated to 'false'
   450 |  requires is_bounded_array_v<remove_reference_t<_Tp>> || __member_end<_Tp>
       |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 /usr/include/c++/10/bits/range_access.h:450:58: note: the operand '__member_end<_Tp>' is unsatisfied because
   450 |  requires is_bounded_array_v<remove_reference_t<_Tp>> || __member_end<_Tp>
       |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~
   451 |  || __adl_end<_Tp>
       |  ~~~~~~~~~~~~~~~~~                                        
 /usr/include/c++/10/bits/range_access.h:416:15:   required for the satisfaction of '__member_end<_Tp>' [with _Tp = char&]
 /usr/include/c++/10/bits/range_access.h:416:30:   in requirements with 'char& __t'
 /usr/include/c++/10/bits/range_access.h:418:18: note: the required expression 'std::__detail::__decay_copy(__t.end())' is invalid, because
   418 |    { __decay_copy(__t.end()) }
       |      ~~~~~~~~~~~~^~~~~~~~~~~
 /usr/include/c++/10/bits/range_access.h:418:23: error: request for member 'end' in '__t', which is of non-class type 'char'
   418 |    { __decay_copy(__t.end()) }
       |                   ~~~~^~~
 /usr/include/c++/10/bits/range_access.h:451:5: note: the operand '__adl_end<_Tp>' is unsatisfied because
   450 |  requires is_bounded_array_v<remove_reference_t<_Tp>> || __member_end<_Tp>
       |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   451 |  || __adl_end<_Tp>
       |  ~~~^~~~~~~~~~~~~~
 In file included from /usr/include/c++/10/compare:39,
                  from /usr/include/c++/10/bits/stl_pair.h:65,
                  from /usr/include/c++/10/bits/stl_algobase.h:64,
                  from /usr/include/c++/10/bits/char_traits.h:39,
                  from /usr/include/c++/10/string_view:41,
                  from file.h:4,
                  from file.cpp:1:
 /usr/include/c++/10/concepts:119:10:   required for the satisfaction of '__class_or_enum<typename std::remove_reference<_Tp>::type>' [with _Tp = char&]
 /usr/include/c++/10/bits/range_access.h:426:15:   required for the satisfaction of '__adl_end<_Tp>' [with _Tp = char&]
 /usr/include/c++/10/concepts:120:41: note: no operand of the disjunction is satisfied
   120 |    = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
       |      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~
 /usr/include/c++/10/concepts:120:6: note: the operand 'is_class_v<_Tp>' is unsatisfied because
   120 |    = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
       |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 /usr/include/c++/10/concepts:119:10:   required for the satisfaction of '__class_or_enum<typename std::remove_reference<_Tp>::type>' [with _Tp = char&]
 /usr/include/c++/10/bits/range_access.h:426:15:   required for the satisfaction of '__adl_end<_Tp>' [with _Tp = char&]
 /usr/include/c++/10/concepts:120:6: note: the expression 'is_class_v<_Tp> [with _Tp = char]' evaluated to 'false'
   120 |    = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
       |      ^~~~~~~~~~~~~~~
 /usr/include/c++/10/concepts:120:25: note: the operand 'is_union_v<_Tp>' is unsatisfied because
   120 |    = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
       |      ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 /usr/include/c++/10/concepts:119:10:   required for the satisfaction of '__class_or_enum<typename std::remove_reference<_Tp>::type>' [with _Tp = char&]
 /usr/include/c++/10/bits/range_access.h:426:15:   required for the satisfaction of '__adl_end<_Tp>' [with _Tp = char&]
 /usr/include/c++/10/concepts:120:25: note: the expression 'is_union_v<_Tp> [with _Tp = char]' evaluated to 'false'
   120 |    = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
       |                         ^~~~~~~~~~~~~~~
 /usr/include/c++/10/concepts:120:44: note: the operand 'is_enum_v<_Tp>' is unsatisfied because
   120 |    = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
       |      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~
 /usr/include/c++/10/concepts:119:10:   required for the satisfaction of '__class_or_enum<typename std::remove_reference<_Tp>::type>' [with _Tp = char&]
 /usr/include/c++/10/bits/range_access.h:426:15:   required for the satisfaction of '__adl_end<_Tp>' [with _Tp = char&]
 /usr/include/c++/10/concepts:120:44: note: the expression 'is_enum_v<_Tp> [with _Tp = char]' evaluated to 'false'
   120 |    = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
       |                                            ^~~~~~~~~~~~~~

有没有一种简单的方法可以使用带有 C++20 范围的分隔符来连接这些字符串?是不是因为字符串是临时的?

【问题讨论】:

  • This answer 是你想要的。你需要cache1
  • @Barry 是否在标准范围内提供cache1
  • cache1 在标准范围内不可用。链接答案上方是一个旧的解决方法。
  • @Fureeish 解决方法使用ranges::compose,它也不在标准范围内......还有另一种简单的方法来处理这种事情吗?
  • 我错过了那部分,对不起。不幸的是,我既无法找到 ranges::composeEric's manual 中所做的事情,也无法查看 libraries code

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


【解决方案1】:

C++23 采用了views::join_with,并且P2328 使views::join 加入了prvalue 非视图范围的范围(这意味着在这种情况下我们不再需要cache1),所以你的例子现在很好- 用 C++23 形成(稍作修改):

/*const*/ auto result = data
    | std::views::reverse
    | std::views::transform([](auto byte) { return fmt::format("{:02x}", byte); })
    | std::views::join_with(':');

注意join_with_view 在这种情况下会在内部缓存纯右值范围,因此它不再是 const-iterable。

Demo(使用实现provided by the original paper

【讨论】:

  • C++23 范围感觉会好很多
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-20
  • 2013-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-23
相关资源
最近更新 更多