Объединение диапазона строк с разделителем с использованием стандартных диапазонов
Я хочу преобразовать четыре байта, содержащиеся в диапазоне, в строку, используя диапазоны. Вот пример ввода и вывода:
std::span<std::byte> data{bytes}; // contains 0x11, 0x22, 0x33, 0x44
std::string result = ...; // results in 44:33:22:11
Вот что я придумал, следуя ответам в диапазоне-v3, как действовать:: присоединиться с разделителем:
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? Это потому, что струны временные?
1 ответ
С++ 23 принятviews::join_with
, а P2328 сделал
views::join
для объединения диапазонов диапазонов prvalue без просмотра (что означает, что нам больше не нужно
cache1
в таком случае), поэтому ваш пример теперь правильно сформирован на С++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
в таком случае будет кэшировать диапазон prvalue внутри, поэтому он больше не является константным.
Демонстрация (Используйте реализацию , представленную в оригинальной статье )