C++如何实现完美转发pair元素并返回其第二个成员避免悬垂引用
解决方案
核心问题
问题本质是需要根据func()返回的pair本身的值类别,调整第二个元素的返回策略:
- 若pair是左值/右值引用类型(生命周期由外部保证),直接返回第二个元素的对应引用即可
- 若pair是prvalue临时对象:
- 若第二个元素本身是左值引用(其生命周期不与临时pair绑定),保留引用返回
- 若第二个元素是值/右值引用(其生命周期与临时pair绑定),按值返回(移动构造)避免悬垂引用
C++23 极简方案
直接用标准库提供的std::forward_like即可完美处理所有场景,代码非常简洁:
#include <utility> #include <type_traits> #include <iostream> using namespace std; template<typename F> decltype(auto) foo(F&& func) { auto&& pair_res = std::forward<F>(func)(); return std::forward_like<decltype(pair_res)>(get<1>(pair_res)); } pair<int, int> value_of_values() { return make_pair(2, 3); } pair<int &, int &> value_of_refs() { static int x = 4; static int y = 5; return pair<int &, int &>(x, y); } pair<int, int> &ref_of_values() { static pair<int, int> p(6, 7); return p; } int main() { cout << foo(value_of_values) << '\n'; // 输出3,返回值类型为int,无悬垂 cout << foo(value_of_refs) << '\n'; // 输出5,返回值类型为int&,无拷贝 cout << foo(ref_of_values) << '\n'; // 输出7,返回值类型为int&,无拷贝 return 0; }
std::forward_like会自动匹配传入pair的值类别,对prvalue的pair自动返回非引用类型的元素值,其余场景保留原有引用类型,完全符合需求。
C++17 兼容方案
如果需要兼容C++23之前的标准,可以手动实现简化版的转发逻辑:
#include <utility> #include <type_traits> #include <iostream> using namespace std; template <typename PairType, typename ElemType> constexpr decltype(auto) forward_pair_element(ElemType&& elem) noexcept { if constexpr (std::is_reference_v<PairType>) { // pair本身是引用,生命周期外部保证,直接转发元素的引用类型 return std::forward<ElemType>(elem); } else { // pair是prvalue临时对象 if constexpr (std::is_lvalue_reference_v<ElemType>) { // 元素本身是左值引用,生命周期不绑定pair,直接返回 return elem; } else { // 元素生命周期绑定到临时pair,按值返回避免悬垂 return static_cast<std::remove_cvref_t<ElemType>>(std::forward<ElemType>(elem)); } } } template<typename F> decltype(auto) foo(F&& func) { using PairRet = std::invoke_result_t<F&&>; auto&& pair_res = std::forward<F>(func)(); return forward_pair_element<PairRet>(get<1>(pair_res)); } pair<int, int> value_of_values() { return make_pair(2, 3); } pair<int &, int &> value_of_refs() { static int x = 4; static int y = 5; return pair<int &, int &>(x, y); } pair<int, int> &ref_of_values() { static pair<int, int> p(6, 7); return p; } int main() { cout << foo(value_of_values) << '\n'; cout << foo(value_of_refs) << '\n'; cout << foo(ref_of_values) << '\n'; return 0; }
该实现完全覆盖所有测试场景,既不会出现悬垂引用,也不会产生不必要的拷贝。
内容的提问来源于stack exchange,提问作者Bruce Merry
相关产品推荐
相关产品推荐

