康桓瑋*_*康桓瑋 5 c++ range-v3 std-ranges c++23
C++23 引入了非常强大的ranges::to从范围构造对象(通常是容器)的功能,具有以下定义([range.utility.conv.to]):
template<class C, input_\xc2\xadrange R, class... Args> requires (!view<C>)\n constexpr C to(R&& r, Args&&... args);\nRun Code Online (Sandbox Code Playgroud)\n请注意,它仅限制模板参数C不是 a view,也就是说,C甚至可能不是 a range。
然而,它的实现用于range_value_t<C>获取 的元素类型C,这C至少使得模板参数必须对 a 进行建模的给range定约束。range_value_tRrange
那么,为什么ranges::to对模板参数的约束如此宽松C?
我注意到论文的 R3 版本过去常常约束C为input_range,这显然是合理的,因为input_range保证了 是range_value_t格式良好的,但在 R4 中这个约束被删除了。而且我没有找到任何关于此更改的评论。
C那么,消除必须的约束有哪些考虑因素呢input_range?
有没有一个实际的例子来说明这种约束放松的好处?
\n这是我们需要解决的措辞问题,我将在今天晚些时候提出一个问题。这是LWG 3785。
C那么,消除必须的约束有哪些考虑因素呢input_range?
的目标ranges::to是将某个范围收集到......某物中。但它不一定是实际范围。只是消耗所有元素的东西。当然,最常见的用法是实际容器类型,最常见的实际容器类型是std::vector.
不过,还有其他有趣的用例,确实没有太多理由拒绝。
假设我们有一个范围std::expected<int, std::exception_ptr>,称之为results。也许我们进行了大量计算,但其中一些计算失败了。我可以将其收集到一个 中std::vector<std::expected<int, std::exception_ptr>>,这可能会有用。但还有另一种选择:我可以将其收集到std::expected<std::vector<int>, std::exception_ptr>. 也就是说,如果所有计算都成功,我将获得所有结果作为值类型。但是,如果其中任何一个失败,我都会收到第一个错误。这是一件非常有用的事情,它在概念上非常符合ranges::to对其输入所做的事情 - 因此这可以支持:
auto processed = results | ranges::to<std::expected>();
if (not processed) {
std::rethrow_exception(processed.error());
}
std::vector<int> values = std::move(processed).value();
// go do more stuff
Run Code Online (Sandbox Code Playgroud)
这对支持来说非常有用——特别是因为不支持它并不需要付出任何代价。我们只需要不要过早地拒绝它。