使用标准范围将一系列字符串与定界符连接起来
Joining a range of strings with a delimiter using standard ranges
我想使用范围将跨度中包含的四个字节转换为字符串。这是输入和输出的示例:
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 范围的定界符来连接这些字符串?是因为字符串是临时的吗?
C++23 采用 views::join_with
, and P2328 made views::join
加入纯右值 non-view 范围的范围(这意味着在这种情况下我们不再需要 cache1
),所以您的示例现在是 C++23 中的 well-formed(稍作修改):
/*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 (Use the implementation provided by the original paper)
我想使用范围将跨度中包含的四个字节转换为字符串。这是输入和输出的示例:
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 范围的定界符来连接这些字符串?是因为字符串是临时的吗?
C++23 采用 views::join_with
, and P2328 made views::join
加入纯右值 non-view 范围的范围(这意味着在这种情况下我们不再需要 cache1
),所以您的示例现在是 C++23 中的 well-formed(稍作修改):
/*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 (Use the implementation provided by the original paper)