函數傳參
普通函數
非常量引用
在普通函數中,當形參是一個類型的引用時:
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 &
。
這就是模板函數的右值引用形參可以接受一個左值的原因。