如何用std::ranges::to将std::ranges::lazy_split_view转为std::vector?
问题描述
在Rust中可轻松实现字符串按分隔符分割并收集到向量中:
let vec = "Hello-+-Rust-+-!".split("-+-").collect::<Vec<_>>(); println!("{:?}", vec); // 输出: ["Hello", "Rust", "!"]
尝试在C++23中实现相同功能,编写了如下代码:
#include <ranges> #include <vector> #include <print> int main() { auto vec = "Hello-+-C++-+-23-+-!" | std::ranges::views::lazy_split(std::string_view("-+-")) | std::ranges::to<std::vector<std::string_view>>(); std::println("{}", vec); }
但Clang编译时报出两个错误:
In file included from <source>:1: In file included from /opt/compiler-explorer/clang-trunk-20240518/bin/../include/c++/v1/ranges:416: /opt/compiler-explorer/clang-trunk-20240518/bin/../include/c++/v1/__ranges/to.h:134:18: error: no matching function for call to 'to' 134 | return ranges::to<range_value_t<_Container>>(std::forward<decltype(__elem)>(__elem)); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ... /opt/compiler-explorer/clang-trunk-20240518/bin/../include/c++/v1/__ranges/to.h:133:27: error: invalid operands to binary expression ('ref_view<lazy_split_view<ref_view<const char[21]>, string_view>>' (aka 'ref_view<std::ranges::lazy_split_view<std::ranges::ref_view<const char[21]>, std::string_view>>') and '__range_adaptor_closure_t<__bind_back_t<__fn, tuple<(lambda at /opt/compiler-explorer/clang-trunk-20240518/bin/../include/c++/v1/__ranges/to.h:133:46)>>>' (aka 'std::ranges::__range_adaptor_closure_t<std::__bind_back_t<std::ranges::views::__transform::__fn, std::tuple<(lambda at /opt/compiler-explorer/clang-trunk-20240518/bin/../include/c++/v1/__ranges/to.h:133:46)>>>')) 133 | ref_view(__range) | views::transform([](auto&& __elem) { | ~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 134 | return ranges::to<range_value_t<_Container>>(std::forward<decltype(__elem)>(__elem)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 135 | }), | ~~ ... 2 errors generated. ASM generation compiler returned: 1
请问该如何定位问题原因?
问题分析与解决
核心原因
std::ranges::lazy_split返回的视图元素是原字符串的子范围(而非直接的std::string_view)。当你试图用std::ranges::to<std::vector<std::string_view>>转换时,标准库内部尝试将每个子范围直接转为string_view,但没有对应的重载支持这种转换,因此触发编译错误。这是C与Rustsplit的关键差异:Rust的split直接生成字符串切片,而C的lazy_split保留原范围的子区间引用。
修复代码
需要显式通过views::transform将每个子范围转换为std::string_view:
#include <ranges> #include <vector> #include <print> #include <string_view> int main() { auto vec = "Hello-+-C++-+-23-+-!" | std::ranges::views::lazy_split(std::string_view("-+-")) | std::ranges::views::transform([](auto&& subrange) { return std::string_view(subrange.begin(), subrange.end()); }) | std::ranges::to<std::vector<std::string_view>>(); std::println("{}", vec); }
定位思路
- 明确API返回类型:查阅C++23标准或编译器文档,确认
lazy_split的元素类型是子范围,而非字符串类型。 - 拆解错误信息:第一个错误提示“no matching function for call to 'to'”,直接点出子范围转
string_view无匹配重载;第二个错误是内部适配层的连锁问题,根源还是元素类型不匹配。 - 补全类型转换逻辑:手动添加
transform层完成子范围到string_view的转换,确认类型匹配后即可解决编译问题。
内容的提问来源于stack exchange,提问作者Sunshine Li
相关产品推荐
相关产品推荐

