- 作者: 雪山肥鱼
- 时间:20220208 14:45
- 目的: 转发引用
# 万能引用/转发引用
## 类型区别基本含义
## 万能引用 基本认识
## 万能引用资格的剥夺与比那人
## 剥夺
## 辨认
万能引用/转发引用
类型区别基本含义
#if 1 //万能引用
/*
void func(const int & abc) {
}
*/
template <typename T>
void func(const T& abc) {
}
int main(int argc, char ** argv) {
func(10);//T 代表的类型是?T 的类型取决于1. 参数10, 2. abc 的类型 即 const T &
//引出万能引用
return 0;
}
10 传入到函数模板的参数中,到底是声明类型。
- 取决于 10 是声明类型
- 取决于 函数模板参数,abc 是声明类型
引出转发引用,即万能引用
万能引用 基本概念
#include <iostream>
using namespace std;
void myfunc(int && tmprv) {
cout << tmprv << endl;
return;
}
int main(int argc, char ** argv) {
//结论:万能引用是一种类型,跟 int 类型一样
//右值引用是用 &&
//int && rv = 1000;
myfunc(10);//10是一个右值,绑在右值引用上。右值做实参
int i = 100;//i 是左值
myfunc(i);//错误,右值引用不能绑定左值
return 0;
}
右值绑在右值引用,没问题。
左值绑在右值引用,是错误的。
补充:
void test(int &a) {
}
void test2(int && a) {
}
int main(int argc, char **argv) {
test(2);//错误
return 0;
}
形参 int & 只能接左值
形参 int&& 只能接右值
形参 int 左右都能接
- 改造成函数模板
发现,技能接左值,又能接右值
//此时 函数模板既能接左值,又能接右值
template <typename T>
void myfunc(T && tmprv) {//特别注意:&& 和T 没有任何关系
cout << tmprv << endl;
return;
}
int main(int argc, char ** argv) {
myfunc(10);
int i = 100;
//此时不能将T 单纯的认为是int,否则一定会因为左值传右值而报错
myfunc(i);//改成模板后,竟然不报错。
return 0;
}
注意注释所说,不能单纯的认为 T 的类型是int.
T&& 构成了 tmprv 的类型
上述情形即万能i引用:
- 必须是函数模板
- 参数必须发生了类型推断,并且函数模板中的形参类型为 T&&(固定的)
T&& 可以当左值,也可以当右值
- 如果实参是 i,则 T&& 类型被推断为 int &
- 如果实参是10,则 tmprv的类型会被推断为 int &&
void func(int && abc); //非模板 则 右值引用
template <typename T>
void func(T && tmp){} //是万能引用
template <typename T>
void func(vector<T> && param) {} //右值引用 只有T&& 是万能,可以测一下.另一个原因,T 是要参与类型推断的。此处没有参与类型推断
template<typename T>
void func(vector<T> && param) {
}
vector<int> aa = {1};
func(aa); //即可推断出来
根据第3个例子,auto && template = ... 也是万能引用
模板中的形参依旧是左值,是可以进行赋值的
template <typename T>
void myfunc(T && tmprv) {//特别注意:&& 和T 没有任何关系
//tmprv 本身是个左值,是可以被赋值的。
tmprv = 120;
cout << tmprv << endl;
return;
}
int main(int argc, char ** argv) {
int i = 100;
myfunc(i);
cout << i << endl;//120
i = 200;
myfunc(std::move(i));//i 被 变成了 右值,推断为 int&&
return 0;
}
需要注意,此时 模板中 T 类型的变化,在传进来之前可是值传递哟,T 不是单纯的int:
万能引用资格的剥夺与辨认
剥夺
const 会剥夺一个引用成为万能引用的资格,被打回右值引用
template <typename T>
void myfunc(const T && tmprv) {
cout << tmprv << endl;
return;
}
int main(int argc, char ** argv) {
myfunc(10);
int i = 100;
myfunc(i);//报错
myfunc(std::move(i)); //变成右值才可以
return 0;
}
辨认
template <typename T>
class mytest {
public:
void testfunc(T && x) {//不是万能引用,而是右值引用
public:
template <typename T2>
void testfunc(T2 && x) {
}
}
};
int main(int argc, char ** argv) {
mytest<int> mc;
int i = 100;
mc.testfunc(i);//错误,左值绑了右值
mc.testfunc(std::move(i));
mc.testfunc2(i);
return 0;
}
本身是个成员函数,而没有涉及到类型推断,所以不是万能引用.