使用std::views::split分割string_view,GCC10报错:octet无data()/size()方法
你的理解确实存在偏差——std::views::split返回的子范围并不是std::string_view,哪怕原输入是连续的string_view,拆分后的元素也只是一个视图适配器,不会自动提供data()和size()成员函数。GCC 10对C++20 Ranges的实现还不够完善,尤其是split视图的子范围并没有满足contiguous_range概念,这就是编译器报错的原因。
为什么会这样?
std::views::split的返回值是split_view,它的value_type是一个subrange(子范围),这个子范围并不会直接继承原范围的连续特性。在GCC 10中,这个子范围没有实现data()和size()成员,也不满足contiguous_range,所以你无法直接调用这些方法。
修复代码的两种方式
方式1:将子范围显式转换为std::string_view
因为原输入是std::string_view(连续、可随机访问),我们可以把拆分后的子范围转换成string_view,这样就能安全地使用data()和size()了:
#include <ranges> #include <string_view> #include <charconv> #include <array> template<std::size_t Sz> bool to_bytes(std::array<std::uint8_t, Sz> &data, std::string_view string) { auto target = data.rbegin(); for (const auto octet : string | std::views::split('.')) { if (target == data.rend()) { return false; } // 将子范围转换为string_view std::string_view octet_str(octet.begin(), octet.end()); const auto octet_begin = octet_str.data(); const auto octet_end = octet_begin + octet_str.size(); const auto error = std::error_code(std::from_chars(octet_begin, octet_end, *target).ec); if (error) { return false; } ++target; } return target == data.rend(); }
方式2:使用范围库的自由函数(仅限GCC 11+)
如果你能升级到GCC 11或更高版本,split视图的子范围会满足contiguous_range概念,此时可以使用std::ranges::data和std::ranges::size自由函数来获取数据和长度,无需转换:
// 仅适用于GCC 11及以上 const auto octet_begin = std::ranges::data(octet); const auto octet_end = octet_begin + std::ranges::size(octet);
补充说明
你的核心逻辑(从数组末尾反向填充,最后检查是否填满整个数组)是正确的,只是在处理拆分后的子范围时忽略了C++20 Ranges视图的特性——视图本身是惰性的,不会自动转换成我们熟悉的容器/视图类型,需要显式转换或使用范围库的通用函数来操作。
内容的提问来源于stack exchange,提问作者Deedee Megadoodoo

