完美转发是c++11 引入右值引用之后,在template 中的延伸. 顾名思义,完美转发是将参数不改变属性的条件下,转发给下一个函数. 因为普通函数的参数一旦具名,始终都是lvalue. 如果把rvalue转发到下一个函数上的参数中,还是rvalue.这就是完美转发的目的。

#include<iostream>
using namespace std; struct X {};
void inner(const X&) {cout << "inner(const X&)" << endl;}
void inner(X&&) {cout << "inner(X&&)" << endl;}
template<typename T>
void outer(T&& t) {inner(forward<T>(t));} int main()
{
X a;
outer(a);
outer(X());
inner(forward<X>(X()));
}
//inner(const X&)
//inner(X&&)
//inner(X&&)

那么如何支持完美转发呢?第一反应就是用通用引用;假设如此实现:

template<class T>
T&& forwarding(T&& t){
return static_cast<T&&>(param);
}

 传入左值的时候是forward(x), 传入右值是forward(X()),看起来符合要求。但是这里用错了完美转发的具体场景,也就是通常我们用完美转发是什么形式呢?如果不使用完美转发,那么在template function会出现什么情况?

template <typename T>
void relay(T&& t) {
cout << "in relay" << endl;
func(t);
}

 relay(temp());传入的是右值,但是转发的时候t被认为左值. 不符合完美转发语义

template<typename T>
void foo(T&& fparam)
{
std::forward<T>(fparam);
}

  

 以上是完美转发的场景,完美转发配套通用引用,才是它的应用场景, 因为param已经具名,所以是lvalue,刚才的简单实现,显然不符合。

template <typename T>
T&& forward(typename remove_reference<T>::type& param)
{
return static_cast<T&&>(param);
}

 以上实现,才是完美转发的主要实现,为什么是主要实现,因为它是最多场景的实现。我们分析一下foo(A());T被推导为A,fparam是lvalue,param是A&。因此匹配

但是如果我们翻C++ 完美转发的实现:貌似还有另外一个实现:
template <class T> T&& forward(typename remove_reference<T>::type&& t) noexcept;
这里应对什么场景呢?直接调用forward<A>(A())的场景。 注意这里typename remove_reference<T>::type&&不再是通用引用,而是右值引用。之前的左值引用,不能接右值,所以需要重定义一个函数.

以上就实现了完美转发的所有内容.完美转发的根基是引用折叠和通用引用.
   其他:
template< class T > struct remove_reference      {typedef T type;};
template< class T > struct remove_reference<T&> {typedef T type;};
template< class T > struct remove_reference<T&&> {typedef T type;};

  

c++11 perfect forwarding的更多相关文章

  1. 翻译「C++ Rvalue References Explained」C++右值引用详解 Part8:Perfect Forwarding(完美转发):解决方案

    本文为第八部分,目录请参阅概述部分:http://www.cnblogs.com/harrywong/p/cpp-rvalue-references-explained-introduction.ht ...

  2. C++11--右值引用(Perfect Forwarding)

    /* * 右值引用 2: Perfect Forwarding */ void foo( boVector arg ); // boVector既有移动构造又有拷贝构造 template< ty ...

  3. C++: Perfect Forwarding

    Link: Rvalue References and Perfect Forwarding in C++0x (https://www.justsoftwaresolutions.co.uk/cpl ...

  4. 完美转发(perfect forwarding)、universal reference、引用折叠(collasping)

    首先要分清: C++里的值只有两种值:左值.右值.—— 其本质应该是内存中存储的值/instance分两种:一种是持久的,一种是“短暂的” 也只有两种引用: 左值引用.右值引用. ——引用,就是这个内 ...

  5. Effective Modern C++ 42 Specific Ways to Improve Your Use of C++11 and C++14

    Item 1: Understand template type deduction. Item 2: Understand auto type deduction. Item 3: Understa ...

  6. 【转】C++11 标准新特性: 右值引用与转移语义

    VS2013出来了,对于C++来说,最大的改变莫过于对于C++11新特性的支持,在网上搜了一下C++11的介绍,发现这篇文章非常不错,分享给大家同时自己作为存档. 原文地址:http://www.ib ...

  7. c++11 中的 move 与 forward

    [update: 关于左值右值的另一点总结,请参看这篇] 一. move 关于 lvaue 和 rvalue,在 c++11 以前存在一个有趣的现象:T&  指向 lvalue (左传引用), ...

  8. [转载] C++11新特性

    C++11标准发布已有一段时间了, 维基百科上有对C++11新标准的变化和C++11新特性介绍的文章. 我是一名C++程序员,非常想了解一下C++11. 英文版的维基百科看起来非常费劲,而中文版维基百 ...

  9. C++ 11和C++98相比有哪些新特性

    此文是如下博文的翻译: https://herbsutter.com/elements-of-modern-c-style/ C++11标准提供了许多有用的新特性.这篇文章特别针对使C++11和C++ ...

随机推荐

  1. 怎样用jQuery拿到select中被选中的option的值

    1.首先要保证select中每一个option标签都有value属性: 2.jquery的写法 1 $('#sele').val()//这里假设select的id是sele,这样可以获取当前选中的op ...

  2. hive1.2.1问题集锦

    1.启动hive报错: Logging initialized using configuration in jar:file:/usr/local/hive-1.2.1/lib/hive-commo ...

  3. [Groovy] Groovy API

    http://www.soapui.org/about-soapui/soapui-faq.html#1-SoapUI--General-Questions 3.1.1. What is Groovy ...

  4. ceph修复osd为down的情况

    尝试一.直接重新激活所有osd 1.查看osd树 root@ceph01:~# ceph osd tree ID WEIGHT TYPE NAME UP/DOWN REWEIGHT PRIMARY-A ...

  5. 编写高质量代码改善C#程序的157个建议——建议89:在并行方法体中谨慎使用锁

    建议89:在并行方法体中谨慎使用锁 除了建议88所提到的场合,要谨慎使用并行的情况还包括:某些本身就需要同步运行的场合,或者需要较长时间锁定共享资源的场合. 在对整型数据进行同步操作时,可以使用静态类 ...

  6. Tomcat之Web站点部署

    上线代码有两种方式,第一种方式是直接将程序目录放在webapps目录下面,这种方式大家已经明白了,就不多说了.第二种方式是使用开发工具将程序打包成war包,然后上传到webapps目录下面.下面让我们 ...

  7. Linq聚合操作之Aggregate,Count,Sum,Distinct源码分析

    Linq聚合操作之Aggregate,Count,Sum,Distinct源码分析 一:Linq的聚合运算 1. 常见的聚合运算:Aggregate,Count, Sum, Distinct,Max, ...

  8. Linq生成操作之DefautIfEmpty,Empty,Range,Repeat源码分析

    Linq生成操作之DefautIfEmpty,Empty,Range,Repeat源码分析 Linq的四种生成运算 DefautIfEmpty,Empty,Range,Repeat 也就是给我们初始化 ...

  9. java 调用javascript

    首先我们在D盘的根目录下有一个js文件 名叫 common.js 假设里面有一个这样的方法 /** * @param int *            _number 你想要的最大值 * @param ...

  10. IO--RAID

    RAID IO计算 Raid 0 –每个磁盘的I/O计算= (读+写) /磁盘个数 Raid 1 --每个磁盘的I/O计算= [读+(2*写)]/2 Raid 5 --每个磁盘的I/O计算= [读+( ...