如何避免传入的临时vector被std::ranges移动
问题分析与解决方法
核心原因
你遇到的是C++20范围库的设计行为:当std::views::all接收右值类型的非视图容器(比如你传入的临时vector)时,会通过std::ranges::owning_view接管容器所有权,这会触发容器的移动构造,导致原容器被清空。而你用std::forward<T>(ts)把右值参数转发给views::all,正好命中了这个逻辑。
解决办法
方案1:直接使用参数作为左值(最简洁)
修改视图创建代码,去掉std::forward<T>,直接使用参数ts:
template<std::ranges::viewable_range T> auto foo(T&& ts) -> size_t { auto moves_ts { ts | std::views::all }; return ts.size(); }
转发引用的参数ts本身是左值(即使它的类型是右值引用),直接使用ts会让views::all生成std::ranges::ref_view——它只会引用容器,不会触发移动。不管你传入左值变量还是临时右值容器,原容器的状态都不会被改变。
方案2:显式转为左值引用(保留转发逻辑时用)
如果函数其他地方需要用到std::forward,可以显式把参数转为左值引用后再传给views::all:
template<std::ranges::viewable_range T> auto foo(T&& ts) -> size_t { // 转为左值引用,避免移动 auto moves_ts { static_cast<T&>(ts) | std::views::all }; // 如果不需要修改容器,也可以用const左值引用: // auto moves_ts { std::as_const(ts) | std::views::all }; return ts.size(); }
这种方式同样能确保views::all拿到的是左值引用,不会触发owning_view的移动构造。
内容的提问来源于stack exchange,提问作者mheyman
相关产品推荐
相关产品推荐

