C++20中返回含unique_ptr引用的std::pair编译错误求助
unique_ptr引用的std::pair编译失败 问题背景
使用C++20、GCC 11.1.0环境,尝试实现类方法返回由uint32_t和unique_ptr引用组成的std::pair,其中unique_ptr来自类内存储的unique_ptr向量,但编译报错。
编译错误信息
error: could not convert ‘std::make_pair(_T1&&, _T2&&) [with _T1 = unsigned int; _T2 = std::unique_ptr
&; typename std::__strip_reference_wrapper<typename std::decay<_Tp2>::type>::__type = std::unique_ptr ; typename std::decay<_Tp2>::type = std::decay<std::unique_ptr &>::type; typename std::__strip_reference_wrapper<typename std::decay<_Tp>::type>::__type = unsigned int; typename std::decay<_Tp>::type = unsigned int]((* &((Screen*)this)->Screen::panels.std::vector<std::unique_ptr >::emplace_back<>()))’ from ‘pair<[...],std::unique_ptr >’ to ‘pair<[...],std::unique_ptr &>’
67 | return std::make_pair<PanelID, Panel_Ptr&>(
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
| |
| pair<[...],std::unique_ptr>
68 | std::move(panelID), panels.emplace_back());
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
相关代码
class Screen { private: using PanelID = uint32_t; using Panel_Ptr = std::unique_ptr<Panel>; std::vector<Panel_Ptr> panels {}; public: std::pair<PanelID, Panel_Ptr&> foo() { PanelID panelID {static_cast<PanelID>(panels.size())}; return std::make_pair<PanelID, Panel_Ptr&>( std::move(panelID), panels.emplace_back()); } };
解决方案
错误原因
std::make_pair内部会对模板参数做decay处理,即使你指定了引用类型,最终也会被剥离,返回的pair存储的是值类型而非引用,和你声明的返回类型std::pair<PanelID, Panel_Ptr&>不匹配。另外,unique_ptr不可拷贝,make_pair处理引用参数时会触发移动,最终生成的是包含unique_ptr值的pair,无法转换成带引用的pair。
修复代码
直接构造std::pair来精确控制成员类型,不要用std::make_pair:
std::pair<PanelID, Panel_Ptr&> foo() { PanelID panelID {static_cast<PanelID>(panels.size())}; auto& new_panel = panels.emplace_back(); return {panelID, new_panel}; }
或者显式指定pair类型构造:
return std::pair<PanelID, Panel_Ptr&>(panelID, panels.emplace_back());
额外优化
std::move(panelID)是多余的——PanelID是基础类型,移动和拷贝性能完全一致,直接传递panelID即可。
注意事项
- 返回的
unique_ptr引用依赖Screen对象的生命周期,必须保证使用该引用时Screen对象仍有效,避免悬空引用。 - 当需要精确控制
pair成员的引用、const等修饰时,直接构造std::pair比std::make_pair更可靠,后者更适合自动推导简单类型的场景。
内容的提问来源于stack exchange,提问作者spaL

