如何在编译期将std::views::join的执行结果转换为string_view?
问题原因说明
- 你现有可运行的代码本身存在未定义行为:
std::views::split+std::views::join得到的是跳过分隔符的非连续范围,迭代器不会连续指向原字符串的存储,你直接取首迭代器地址+长度构造string_view,得到的内容和你预期的join后结果完全不一致,只是刚好运行时没有触发崩溃而已。 - 加
constexpr修饰符后编译失败的核心原因:C20标准中绝大多数range适配器不支持const迭代(cbegin()/const begin()),该特性是C23才正式标准化的,同时大量range相关操作的constexpr支持也是C++23才完善的。
解决方案
方案1:截取前四个单词(保留中间空格,C++20即可支持)
如果你的真实需求是获取原字符串中前四个单词及单词间的空格,完全不需要使用split+join组合,直接在编译期计算第四个空格的下标即可,写法简单无UB:
#include <iostream> #include <string_view> int main() { constexpr std::string_view words{"Just some sentence I got from a friend."}; // 编译期计算前四个单词的区间 constexpr std::string_view first_four_words = []() -> std::string_view { std::size_t space_cnt = 0; for (std::size_t i = 0; i < words.size(); ++i) { if (words[i] == ' ' && ++space_cnt == 4) { return words.substr(0, i); } } return words; }(); // 编译期校验结果正确性 static_assert(first_four_words == "Just some sentence I"); std::cout << first_four_words << std::endl; }
方案2:拼接前四个单词(去掉空格,C++23支持)
如果你确实需要将前四个单词去掉空格后拼接,可以使用C++23完善的constexpr range特性,配合编译期数组存储结果,完全避免丑陋的指针写法:
#include <iostream> #include <ranges> #include <string_view> #include <array> int main() { constexpr std::string_view words{"Just some sentence I got from a friend."}; // 编译期完成split、take、join逻辑,将结果存入array constexpr auto joined_buf = []() consteval { auto rng = words | std::views::split(' ') | std::views::take(4) | std::views::join; std::array<char, std::ranges::distance(rng) + 1> buf{}; std::ranges::copy(rng, buf.begin()); return buf; }(); constexpr std::string_view first_four_words{joined_buf.data()}; // 编译期校验结果正确性 static_assert(first_four_words == "JustsomesentenceI"); std::cout << first_four_words << std::endl; }
内容的提问来源于stack exchange,提问作者Mr.WorshipMe
相关产品推荐
相关产品推荐

