C++11——完美转发

前置知识,需要你了解

1)模板写法

2)引用折叠

3)移动语义

如果你不具备上述的基础,也许我的这些博客会帮到你

 C++——模板(超详细的模板解析)___JAN__的博客-优快云博客_c++ 模板

C++——C++11的标准(上)___JAN__的博客-优快云博客 


 我们先来看一个C++中最简单的函数重载

void fun(int & a)
{
    cout << "call &" << endl;
}
void fun(int && a)
{
    cout << "call &&" << endl;
}

上面的函数是接受左值的,下面的函数是接受右值的。但是,我们能不能只写一个版本将左值和右值全部接受呢?

可以,如果我们不想要改变形参,我们可以写一个这样的重载版本。

void fun(int & a)
{
    cout << "call &" << endl;
}
void fun(int && a)
{
    cout << "call &&" << endl;
}

请读者记住这个规则,这个规则在模板函数中又会有变化。


完美转发

我们为什么需要完美转发?

你是否记得std::make_shared?你可以传入可变模板参数构造对象。其原理是将参数原封不动的传递给new来构造一个对象。这时候就引申出了一个概念,完美转发。通俗的来讲,完美转发就是将实参原封不动的通过一个中转函数传递给另外一个函数。

我们先看看一些错误的转发

template <typename T1, typename T2>
pair<T1,T2> my_make_pair(const T1 & t1, const T2 & t2)
{
    return {t1,t2}
}

这是一个简单的meke_pair,其使用了const ref的方式来进行传递,避免了不必要的拷贝,很好。

但是,这个函数有一个缺点,如果我们的形参是一个右值,那么在my_make_pair中则变成了一个左值。哦,我们本来像使用移动构造来得到一个pair,现在却没有调用。我们想调用my_make_pair就像直接调用pair的构造函数一样。

在模板中,右值引用是一种万能引用,我们可以使用其接受左值和右值,就像在非模板参数中const &那样。

template <typename T1, typename T2>
pair<T1,T2> my_make_pair(T1 && t1, T2 && t2)
{
    return {t1,t2};
}

不错但是现在这个函数还是有一个问题,很难发现。就是即便我们在形参是右值引用,在接受到参数后,右值引用也很会变为一个左值引用,原因是因为这个右值引用有了名称,或者说其在内存中有了空间,我们可以将其当作左值。

void fun(int & a)
{
    cout << "call &" << endl;
}
void fun(int && a)
{
    cout << "call &&" << endl;
}

void fun(const int & a)
{
    cout << "call const &" << endl;
}

template <typename T1, typename T2>
pair<T1,T2> my_make_pair(T1 && t1, T2 && t2)
{
    return {t1,t2};
}

void print(int & a)
{
    cout << "call &" << endl;
}

void print(int && a)
{
    cout << "call &&" << endl;
}
template <typename T>
void my_forward(T && a)
{
    print(a);
}

可以猜以下输出什么

没错,就是上述所说的结果。

此时T被推断为int类型。即不带任何引用属性的类型。

为了避免这个问题,我们使用std::forward,其返回一个类型的右值引用,根据引用折叠的原理,我们就可以实现完美转发了。

forward是返回类型的右值引用,就是说如果是一个左值,其右值引用就是一个左值。那么forward就是一个左值。如果说T没有任何引用的性质,那么获得的结果就是一个右值,即T&&

template <typename T>
void my_forward(T && a)
{
    print(std::forward<T>(a));
}

上述就是完美转发的全过程了。

 关于参数包的转发,第一个链接中的最后有提到。


参考链接

forward - C++ Reference (cplusplus.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值