You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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);
}

定位思路

  1. 明确API返回类型:查阅C++23标准或编译器文档,确认lazy_split的元素类型是子范围,而非字符串类型。
  2. 拆解错误信息:第一个错误提示“no matching function for call to 'to'”,直接点出子范围转string_view无匹配重载;第二个错误是内部适配层的连锁问题,根源还是元素类型不匹配。
  3. 补全类型转换逻辑:手动添加transform层完成子范围到string_view的转换,确认类型匹配后即可解决编译问题。

内容的提问来源于stack exchange,提问作者Sunshine Li

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 16:53:11