1. 程式人生 > 其它 >Cpp 11 / 萬能引用、引用摺疊和完美轉發

Cpp 11 / 萬能引用、引用摺疊和完美轉發

技術標籤: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 &&param)
{
    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 &param)
{
    std::cout << param << std::endl;
}

template <typename T>
void func(T &&param)
{
    std::cout << param << std::endl;
}

函式形參由於有左值引用和右值引用之分,傳入函式的資料也有左值引用和右值引用的區分,這就分出了 4 種情況。

但是 C++ 是不能對引用進行引用的,故需要一種方案,判定上述 4 種情況下最終的結果是左值引用還是右值引用。

3、解決辦法

為了解決上述問題,誕生了引用摺疊這個概念,也就是判定上述 4 種情況下最終的結果是左值引用還是右值引用的方案,如下:

形參傳入資料結果
&&&
&&&&
&&&&
&&&&&&

可以發現,形參和傳入資料只要有一個是左值引用,其結果就是左值引用;只有全部都是右值引用的情況下其結果才能是右值引用。

4、注意

引用摺疊只能發生在模板函式中,即:編譯期間。

5、栗子

#include <iostream>

template <typename T>
void func_L(T &param)
{
    std::cout << param << std::endl;
}

template <typename T>
void func_R(T &&param)
{
    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 &param)
{
    std::cout << "左值" << std::endl;
}
template <typename T>
void func(T &&param)
{
    std::cout << "右值" << std::endl;
}

template <typename T>
void warp(T &&param)
{
    func(param);
}

int main()
{
    int num = 0;
    warp(num);
    warp(100);
    return 0;
}
左值
左值

3、解決辦法

為了解決上述問題,增加了完美轉發的概念,即:經過轉發之後,資料的引用型別恢復到之前的型別。

4、栗子

#include <iostream>

template <typename T>
void func(T &param)
{
    std::cout << "左值" << std::endl;
}
template <typename T>
void func(T &&param)
{
    std::cout << "右值" << std::endl;
}

template <typename T>
void warp(T &&param)
{
    func(std::forward<T>(param));
}

int main()
{
    int num = 0;
    warp(num);
    warp(100);
    return 0;
}
左值
右值

(SAW:Game Over!)