详解C++完美转发

我们先来看折叠规则

引用折叠规则

在C++中,引用折叠规则的主要目的是为了保证在模板推导过程中,对于参数 T&& 能够正确地推导出其最终的引用类型,以便进行参数传递时的正确行为。下面是引用折叠规则的总结:

  1. 左值引用折叠

    • T& & 折叠为 T&
    • T& && 折叠为 T&

    这意味着如果一个左值引用被再次引用,或者一个左值引用被右值引用引用,最终的结果仍然是左值引用。就是左值怎么引用都是左值。

  2. 右值引用折叠

    • T&& & 折叠为 T&
    • T&& && 折叠为 T&&

    这意味着如果一个右值引用被左值引用引用,最终结果是左值引用;如果一个右值引用被右值引用引用,最终结果仍然是右值引用

了解了折叠规则后,我们来看个demo

template <typename F, typename T1, typename T2>
void flip2(F f, T1 &&t1, T2 &&t2)
{

    f(t1, t2);
}

这个函数模板接受三个参数,并将t1和t2作为f的参数进行调用,给出f的实现

void gtemp(int&& v1, int& v2)
{
    cout << v1 << " " << v2 << endl;
}

调用

int j = 99;
flip2(gtemp, 42, j);
cout << "j is " << j << endl;

得到报错

error C2664: “void (int &&,int &)”: 无法将参数 1 从“T1”转换为“int &&”

分析:42是一个右值对象,j是左值,在flip2中形参t1通过折叠规则推导知类型为右值引用,t2是左值引用,但是将t1作为f的参数时,它依旧是作为一个左值来用的,因此gtemp也就是f调用明显会出错它的第一个参数类型为右值引用,也就是说flip2函数内部把外部实参42作为其他函数的参数传递时,将其的类型给“修改了”,从右值变为左值,这当然不是我们所希望的,那么怎么解决呢?

std::forward<>()函数就是用来保持类型不变的。

再看修改demo

template <typename F, typename T1, typename T2>
void flip2(F f, T1 &&t1, T2 &&t2)
{
    f(std::forward<T1>(t1),std::forward<T2>(t2));
}

forward包含在utility库里,我们使用完美转发函数使t1,t2保持类型与外部实参一致,也就是42(右值),j(int)因此程序正常运行。

posted @ 2024-07-06 16:32  桂洛克船长  阅读(6)  评论(0编辑  收藏  举报