函数传参
普通函数
非常量引用
在普通函数中,当形参是一个类型的引用时:
void f1(int&);
那么,函数f1
可以接受下列形式的实参:
- 一个变量,非const
有名字的变量。 - 返回
int &
类型的表达式或者是函数。
不能是int
不接受常量,或者是匿名变量,比如我们直接传一个1
,不能接受const int
类型的实参。
常量引用
当函数的形参是一个常量引用时:
void f2(const int &);
那么函数f2
可以接受下列形式的实参:
- 一个变量
可以使const,也可是不是 - 常量类型的int
- 匿名变量
直接是数值 - 一个返回int类型的表达式或函数
或是const都行。
可见,常量的形参限制小,但是因为不能改变传入参数的值。
模板函数
值类型
当函数是一个模板的时候:
template <typename T>
void f3(T t);
那么,函数f3
可以接受上面两种普通函数的形式。
因为T
可以被推断为const int
,和int
。
只是值类型的。
引用类型
因此如果,想要声明为引用需要:
template <typename T>
void f4(T&);
这样就和普通函数的第一种形式相同 了。
同时参数也可以是const T&
。
右值引用
上面普通函数的都是左值类型的参数
下面是右值引用
void f(string &&);
普通函数的右值引用可以接受下列形式的实参:
- 常量表达式
一个数字,字符串等.1
,haha
. - 匿名变量
string("123")
- 返回string的函数或表达式
相当于一个匿名变量 - move()语义
但是不能接受变量,也就是不能接受左值。
模板参数的右值引用形参
template <typename T>
void f5(T&&);
当函数是一个模板函数的时候,当他的形参是右值引用的时候有如下的不同:
- 传入左值,传入值的类型被推断为类型的引用
比如,传入string类型
,那么T被推断为string&
同时,引用折叠:怎么说,意思就是左值引用的引用就等于引用,也是是,所有的双数引用可以折叠为右值引用。
而所有单数的引用可以折叠为左值引用
T&& && &&=T&&
T&& && && & =T&
因此,综上棉量两点:
当T = string &&
是,传入的参数类型为string& &&
,因此被折叠为string &
。
这就是模板函数的右值引用形参可以接受一个左值的原因。