如何用std::ranges::to将范围转换为std::array?
std::ranges::to<std::vector>那样优雅转换编译期已知大小的视图到std::array? 我想把以下用std::ranges::to转换为std::vector的代码,改成转换为std::array,但发现std::ranges::to不支持直接转std::array:
constexpr auto dice = std::views::iota(1, 7); static_assert(dice.size() == 6); std::print("{} ", dice | std::ranges::to<std::vector>());
我知道可以显式构造std::array,但这种方式重复且不够优雅,不符合和std::vector用法对称的需求:
constexpr auto arr = [&]() { std::array<std::ranges::range_value_t<decltype(dice)>, dice.size()> result; std::ranges::copy(dice, result.begin()); return result; }(); std::print("{} ", arr);
我尝试过自定义辅助函子,但因无法传递constexpr参数失效;还实现了一个模板函数,但不够优雅:
template<auto& rng> consteval auto to_arr() -> std::array<std::ranges::range_value_t<decltype(rng)>, std::ranges::size(rng)> { std::array<std::ranges::range_value_t<decltype(rng)>, rng.size()> result; std::ranges::copy(rng, result.begin()); return result; }
请问是否存在更简洁、与std::vector用法对称的转换方式?(此问题针对所有编译期已知大小的视图,如transform后的视图)
C++20/23标准中的std::ranges::to确实不支持直接推导std::array的大小——因为std::array的尺寸是模板参数,而ranges::to的原生设计针对的是可动态分配的容器。不过有几种方案能实现接近你需求的优雅转换:
1. 扩展std::ranges::to适配std::array
通过给标准命名空间添加std::array的to特化,实现和vector完全一致的语法:
namespace std::ranges { template<std::ranges::range R> requires std::ranges::sized_range<R> && std::is_constant_evaluated() constexpr auto to<std::array>(R&& r) { using ValueType = std::ranges::range_value_t<R>; constexpr size_t Size = std::ranges::size(r); std::array<ValueType, Size> arr; std::ranges::copy(std::forward<R>(r), arr.begin()); return arr; } }
使用时和原vector写法完全对称:
std::print("{} ", dice | std::ranges::to<std::array>());
注意:扩展标准命名空间在实际项目中可行,但需确认编译器兼容性。
2. 自定义管道适配器to_array
实现一个独立的管道操作符,语法和ranges::to<vector>完全对齐,且无需修改标准库:
struct to_array_t { template<std::ranges::input_range R> requires std::ranges::sized_range<R> && std::is_constant_evaluated() constexpr auto operator()(R&& r) const { using ValueType = std::ranges::range_value_t<R>; constexpr size_t Size = std::ranges::size(r); std::array<ValueType, Size> arr; std::ranges::copy(std::forward<R>(r), arr.begin()); return arr; } }; inline constexpr to_array_t to_array;
使用示例:
std::print("{} ", dice | to_array);
这个方案支持所有编译期尺寸已知的视图,语法简洁且符合你的对称需求。
3. 等待C++26原生支持
目前C标准委员会正在讨论让std::ranges::to原生支持std::array的推导,C26标准中大概率会加入此功能,届时可以直接使用std::ranges::to<std::array>而无需额外代码。
内容的提问来源于stack exchange,提问作者NoSenseEtAl

