C++11:右值

在template的声明式中,class和typename没区别

但如果要在模板参数内部,要typename定义嵌套从属类型的时候 就要typename指定从属类型
比如模板函数里面还有一个类型比如 T::const_iterator* x;如果没用typename的话就可能会被编译器识别为静态成员,就会有二义性,为了让这个T::const_iterator成为T中的一个类型,而不是静态成员就要直接在前面加个typename:

template<typename T>
void Func(const T& arg)
{
    typename T:: const_iterator* x;
}

编译器就能知道这个是一个类型

下面开始C++11标准

右值引用

左值和右值,左值引用和右值引用是C++11中重要概念,是理解move/forward等新语义的基础

左值:
        既能出现在赋值符号“=”左边也能出现在右边的变量或表达式

右值:
        只能出现在赋值符“=”右边的的变量(或表达式)

判断标准:
        一般,有名字的变量就是左值,而由运算符操作所产生的中间结果(没有名字)就是右值,左值就是程序中能寻址的东西,右值就是没办法寻址的东西

在C++11中所有的值必属于左值、纯右值、将亡值之一。比如临时变量、(函数返回值的临时变量、运算表达式产生的临时变量)原始字面量等都是纯右值。而将亡值是C++11与右值引用相关的表达式(将要被移动的对象、std::move返回值等)

什么是左值引用

引用就是某一变量的别名,对引用的操作与对变量直接操作完全一样

对左值的引用叫做左值引用,就是之前学过的引用(变量别名),为了和新标椎中引入的“右值引用”相区别,所以现在叫左值引用

type& name = 左值表达式;

什么是右值引用

对右值(不能取值)的引用叫右值引用

type && name = 右值表达式;

​
int && a1=0;
int && a2 = GetVal();
int val = 100;
int && a3 = val;//? 不成立 但可以用std::move转化

void func(int && val)
{
    std::cout<<val<<std::endl;
}

​

右值引用独立于右值和左值,虽然是对右值的引用,但他本身还是个左值 比如a1 a2就是左值

func(a1); 会直接报错  但可以传GetVal()

意义

右值引用绑定了右值,让临时右值的声明周期延长了(续命),可以利用这个特点避免临时对象的拷贝构造和析构,优化性能

常量左值引用也可以性能优化。输出结构和右值引用相同,因为常量左值引用是一个“万能”的引用类型,可以接受左值、右值、常量左值和常量右值
const int &res = GetVal();//也没拷贝了

在C++11以前右值能被const类型的引用所指向

通用引用

定义函数形参的时候,可以指定:
右值引用:
        void f(int && arg);//右值引用,不能传左值
左值引用:
        void f(int &arg);//左值引用,不能传右值
通用引用:
        void f(T && arg);//通用引用,类型为模板参数
        如果被一个左值初始化,他就是左值,如果被一个右值初始化,他就是一个右值,取决于它的初始化

template<typename T>
void f(T &&arg);
int i = 10;
f(i);  //左值
f(10); //右值 

引用折叠规则

模板函数:
        template<typename T>
        void f (T&& arg);//通用引用,如果T本身也是引用 比如 T&,或者T&&,那么原函数就会展开为:T& &&和 T&& &&
        void f2(T & arg);T本身就是 T& ,T&& 那么展开为 T& &,和T&& &

引用折叠规则:
        x& &,x& &&,x&& &折叠为:x&(单个和单个,单个和双个)
        x&& && 折叠为 X&&(双个和双个)

引用折叠解释通用引用:
int i = 10;
f(i); i: int & -> int & &&->int &
f(10); 10 : int -> int&& 

完美转发

完美转发: 在函数模板中,完全依照模板的参数类型(左值,右值特征),将参数传给函数模板中调用的另外一个函数

void process(int&t){cout<<“lvalue”;}
void process(int&&t){cout<<"rvalue";}

template<typename T>
void Test(T&& v)//是Universal引用,既可以是左值,也可以是右值,左值转发给左值函数,右值转发给右值函数
{
	//转发1:不完美转发
	process(v);//v具有变量,本身是左值,调用process(int &t)

	//转发2: 完美转发
	process(std::forward<T>(v));//按v被初始化时的类型转发(左值或右值)

	//转发3:强制将V转为右值
	process(std::move(v));//将v强制转为右值,调用process(int&& t)
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

#A#

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值