Cpp 11 / 萬能引用、引用摺疊和完美轉發
阿新 • • 發佈:2020-12-10
技術標籤:C/Cpp / 11 、14、……
一、萬能引用
1、英文:Universal Reference 。
2、誕生的原因
因為 C++ 中存在左值引用和右值引用,導致若想同時實現既可傳入左值又可傳入右值的功能,需要對相同函式進行過載,導致程式碼冗餘。
3、解決辦法
為了解決上述問題,就誕生了萬能引用,具體用法如下:
template<typename T>
void func(T&& param) {
;
}
主要實現方法是依靠 C++ 強大的模板推導能力,在編譯期間確定 param 是左值還是右值。
4、擴充套件
&&,在模板形參列表中代表萬能引用,在其他地方就代表右值引用。
5、栗子
#include <iostream>
template <typename T>
void func(T &¶m)
{
std::cout << param << std::endl;
}
int main()
{
int num = 0;
func(num);
func(100);
return 0;
}
0
100
二、引用摺疊
1、英文:Reference Collapse 。
2、誕生的原因
模板函式:
template <typename T> void func(T ¶m) { std::cout << param << std::endl; } template <typename T> void func(T &¶m) { std::cout << param << std::endl; }
函式形參由於有左值引用和右值引用之分,傳入函式的資料也有左值引用和右值引用的區分,這就分出了 4 種情況。
但是 C++ 是不能對引用進行引用的,故需要一種方案,判定上述 4 種情況下最終的結果是左值引用還是右值引用。
3、解決辦法
為了解決上述問題,誕生了引用摺疊這個概念,也就是判定上述 4 種情況下最終的結果是左值引用還是右值引用的方案,如下:
形參 | 傳入資料 | 結果 |
& | & | & |
& | && | & |
&& | & | & |
&& | && | && |
可以發現,形參和傳入資料只要有一個是左值引用,其結果就是左值引用;只有全部都是右值引用的情況下其結果才能是右值引用。
4、注意
引用摺疊只能發生在模板函式中,即:編譯期間。
5、栗子
#include <iostream>
template <typename T>
void func_L(T ¶m)
{
std::cout << param << std::endl;
}
template <typename T>
void func_R(T &¶m)
{
std::cout << param << std::endl;
}
int getvalue()
{
return 100;
}
int main()
{
int num = 0;
int &&num_r = getvalue();
func_L(num);
func_L(num_r);
func_R(num);
func_R(200);
return 0;
}
0
100
0
200
三、完美轉發
1、英文:Perfect Forwarding 。
2、誕生的原因
經過上述引用摺疊之後,傳之前的資料的引用型別和傳入之後的引用型別可能發生變化,怎麼才能保持引用型別呢?如下:
#include <iostream>
template <typename T>
void func(T ¶m)
{
std::cout << "左值" << std::endl;
}
template <typename T>
void func(T &¶m)
{
std::cout << "右值" << std::endl;
}
template <typename T>
void warp(T &¶m)
{
func(param);
}
int main()
{
int num = 0;
warp(num);
warp(100);
return 0;
}
左值
左值
3、解決辦法
為了解決上述問題,增加了完美轉發的概念,即:經過轉發之後,資料的引用型別恢復到之前的型別。
4、栗子
#include <iostream>
template <typename T>
void func(T ¶m)
{
std::cout << "左值" << std::endl;
}
template <typename T>
void func(T &¶m)
{
std::cout << "右值" << std::endl;
}
template <typename T>
void warp(T &¶m)
{
func(std::forward<T>(param));
}
int main()
{
int num = 0;
warp(num);
warp(100);
return 0;
}
左值
右值
(SAW:Game Over!)