为何使用range-v3的concat拼接仅移动类型视图前需先求值?
问题原因解析
你的代码编译差异本质是两种写法下range迭代器的引用类型和仅移动类型的匹配问题,具体如下:
第一种写法编译失败的原因
你直接拼接的v和w是views::transform返回的视图,它的迭代器operator*会返回lambda表达式生成的临时std::unique_ptr<int>,属于纯右值。
views::concat对输入range的引用类型有隐式要求:所有输入range的引用类型需要能安全转换为统一的公共引用类型。std::unique_ptr是仅移动类型,无法拷贝,而range-v3的concat实现对于返回纯右值的input range,默认无法将临时对象的所有权正确转移到输出迭代器,因此触发编译错误。
当你把std::unique_ptr换成可拷贝的std::shared_ptr时,临时对象可以直接拷贝构造,不会触发所有权转移的冲突,因此可以正常编译。
第二种写法编译成功的原因
你先将transform视图求值为std::vector<std::unique_ptr<int>>,此时vector迭代器的operator*返回的是左值引用std::unique_ptr<int>&。
后续你使用了views::move,它会把迭代器的引用类型转换为右值引用std::unique_ptr<int>&&,显式标记元素允许被移动。此时concat可以正确识别右值引用类型,遍历过程中直接移动构造元素到最终的vector中,因此编译正常。
关于viewable_range的补充说明
你对viewable_range的判断是正确的,第一种写法的v和w本身就是transform视图,天然满足viewable_range和input_range的约束,问题并不出在这两个概念的校验上。
内容的提问来源于stack exchange,提问作者Michael Jung
相关产品推荐
相关产品推荐

