右值引用
無名右值引用
- 無名右值引用是右值。
- 無名右值引用的產(chǎn)生方式:
// v是具名右值引用,返回值為無名右值引用
int && fun(int && v) {
return 0;
}
-
std::move
和std::forward
返回的右值引用為無名右值引用,其原理與上述代碼類似。
具名右值引用
- 具名右值引用是左值。
- 具名右值引用只能綁定右值,其定義方式:
// v是具名右值引用,返回值為無名右值引用
int && fun(int && v) {
return 0;
}
int main() {
int x1 = 0;
int & x2 = x1;
int && x3 = 0; // 具名右值引用是左值
int && y1 = x1; // 錯(cuò)誤,無法將右值引用綁定到在左值
int && y2 = x2; // 錯(cuò)誤,無法將右值引用綁定到在左值
int && y3 = x3; // 錯(cuò)誤,無法將右值引用綁定到在左值
int && y4 = fun(0); // fun()返回?zé)o名右值引用,是右值
int && y5 = std::move(0); // std::move()返回?zé)o名右值引用,是右值
return system("pause");
}
轉(zhuǎn)發(fā)型引用
描述
- 轉(zhuǎn)發(fā)型引用可以保留被引用值的
const
、&
、&&
屬性。 - 轉(zhuǎn)發(fā)型引用可以引用任意值,不論是右值、左值、有無
const
等。
定義
方式一
// T &&類型參數(shù)t叫轉(zhuǎn)發(fā)型引用
template <typename T>
void fun(T && t) {
}
方式二
const int && x = 0;
auto && xx = x; // 推斷為const int &,注意x在初始化以后就是const int &類型了
推導(dǎo)規(guī)則
const int x1 = 1;
const int & x2 = x1;
const int && x3 = 1;
int x4 = 1;
int & x5 = x4;
int && x6 = 1;
auto && y1 = x1; // 推斷為const int &
auto && y2 = x2; // 推斷為const int &
auto && y3 = x3; // 推斷為const int &
auto && y4 = x4; // 推斷為int &
auto && y5 = x5; // 推斷為int &
auto && y6 = x6; // 推斷為int &
auto && y7 = 0; // 推斷為具名int &&
auto && y8 = std::move(0); // 推斷為具名int &&
std::move()和std::forward()的區(qū)別
-
std::forward()
的必須通過顯式模板實(shí)參來使用。 -
std::move(int)
和std::forward<int>()
和std::forward<int &&>()
完全無任何區(qū)別,都是轉(zhuǎn)換為無名int &&
。 -
std::move(int)
和std::forward<int &>()
的區(qū)別是前者依舊轉(zhuǎn)換為int &&
,而后者轉(zhuǎn)換為int &
。 - 因?yàn)?code>std::forward()的這個(gè)特性,它的通常用法是在模板中使用
std::forward<T>(t)
,并且T
由T && t
的方式捕獲以實(shí)現(xiàn)完美轉(zhuǎn)發(fā)。
完美轉(zhuǎn)發(fā)
簡述
完美轉(zhuǎn)發(fā):將類型傳遞給模板參數(shù)時(shí),保留所有實(shí)參類型的細(xì)節(jié)(如const,具名右值引用,無名右值引用、左值引用)。
代碼
#include <iostream>
void f(const int & v) {} //fun1
// void f(int & v) { } //fun2
// void f(int && v) { } //fun3
//不完美轉(zhuǎn)發(fā)版本一
template <typename F, typename T>
void call1(F f, T t) {
f(t);
}
//不完美轉(zhuǎn)發(fā)版本二
template <typename F, typename T>
void call2(F f, T && t) {
f(t);
}
//完美轉(zhuǎn)發(fā)
template <typename F, typename T>
void call3(F f, T && t) {
f(std::forward<T>(t));
}
int main() {
const int x1 = 1;
const int & x2 = x1;
const int && x3 = 1;
int x4 = 1;
int & x5 = x4;
int && x6 = 1;
call1(f, x1); //類型參數(shù)推斷為int,丟失類型細(xì)節(jié)信息,轉(zhuǎn)發(fā)失敗。(可以調(diào)用fun2,但不應(yīng)該可以)
call1(f, x2); //類型參數(shù)推斷為int,丟失類型細(xì)節(jié)信息,轉(zhuǎn)發(fā)失敗。(可以調(diào)用fun2,但不應(yīng)該可以)
call1(f, x3); //類型參數(shù)推斷為int,丟失類型細(xì)節(jié)信息,轉(zhuǎn)發(fā)失敗。(可以調(diào)用fun2,但不應(yīng)該可以)
call1(f, x4); //類型參數(shù)推斷為int,丟失類型細(xì)節(jié)信息,轉(zhuǎn)發(fā)失敗。(傳值的方式調(diào)用fun2,但本應(yīng)該用傳引用的方式)
call1(f, x5); //類型參數(shù)推斷為int,丟失類型細(xì)節(jié)信息,轉(zhuǎn)發(fā)失敗。(傳值的方式調(diào)用fun2,但本應(yīng)該用傳引用的方式)
call1(f, x6); //類型參數(shù)推斷為int,丟失類型細(xì)節(jié)信息,轉(zhuǎn)發(fā)失敗。(傳值的方式調(diào)用fun2,但本應(yīng)該用傳引用的方式)
call1(f, 0); //類型參數(shù)推斷為int,丟失類型細(xì)節(jié)信息,轉(zhuǎn)發(fā)失敗。(不可以調(diào)用fun3,但本應(yīng)該可以)
call1(f, std::move(0)); //類型參數(shù)推斷為int,丟失類型細(xì)節(jié)信息,轉(zhuǎn)發(fā)失敗。(不可以調(diào)用fun3,但本應(yīng)該可以)
call2(f, x1); //類型參數(shù)推斷為const int &,轉(zhuǎn)發(fā)時(shí)類型為const int &,轉(zhuǎn)發(fā)成功。
call2(f, x2); //類型參數(shù)推斷為const int &,轉(zhuǎn)發(fā)時(shí)類型為const int &,轉(zhuǎn)發(fā)成功。
call2(f, x3); //類型參數(shù)推斷為const int &,轉(zhuǎn)發(fā)時(shí)類型為const int &,轉(zhuǎn)發(fā)成功。
call2(f, x4); //類型參數(shù)推斷為int &,轉(zhuǎn)發(fā)時(shí)類型為int &,轉(zhuǎn)發(fā)成功。
call2(f, x5); //類型參數(shù)推斷為int &,轉(zhuǎn)發(fā)時(shí)類型為int &,轉(zhuǎn)發(fā)成功。
call2(f, x6); //類型參數(shù)推斷為int &,轉(zhuǎn)發(fā)時(shí)類型為int &,轉(zhuǎn)發(fā)成功。
call2(f, 0); //類型參數(shù)推斷為具名int &&,丟失類型細(xì)節(jié)信息,轉(zhuǎn)發(fā)失敗。(調(diào)用fun3會(huì)出現(xiàn)無法將右值引用綁定到左值的錯(cuò)誤。)
call2(f, std::move(0)); //類型參數(shù)推斷為具名int &&,丟失類型細(xì)節(jié)信息,轉(zhuǎn)發(fā)失敗。(調(diào)用fun3會(huì)出現(xiàn)無法將右值引用綁定到左值的錯(cuò)誤。)
call3(f, x1); //類型參數(shù)推斷為const int &,轉(zhuǎn)發(fā)時(shí)std::forward將類型const int &轉(zhuǎn)換為const int &,轉(zhuǎn)發(fā)成功。
call3(f, x2); //類型參數(shù)推斷為const int &,轉(zhuǎn)發(fā)時(shí)std::forward將類型const int &轉(zhuǎn)換為const int &,轉(zhuǎn)發(fā)成功。
call3(f, x3); //類型參數(shù)推斷為const int &,轉(zhuǎn)發(fā)時(shí)std::forward將類型const int &轉(zhuǎn)換為const int &,轉(zhuǎn)發(fā)成功。
call3(f, x4); //類型參數(shù)推斷為int &,轉(zhuǎn)發(fā)時(shí)std::forward將類型int &轉(zhuǎn)換為int &,轉(zhuǎn)發(fā)成功。
call3(f, x5); //類型參數(shù)推斷為int &,轉(zhuǎn)發(fā)時(shí)std::forward將類型int &轉(zhuǎn)換為int &,轉(zhuǎn)發(fā)成功。
call3(f, x6); //類型參數(shù)推斷為int &,轉(zhuǎn)發(fā)時(shí)std::forward將類型int &轉(zhuǎn)換為int &,轉(zhuǎn)發(fā)成功。
call3(f, 0); //類型參數(shù)推斷為具名int &&,轉(zhuǎn)發(fā)時(shí)std::forward將具名int &&轉(zhuǎn)換為無名int &&,轉(zhuǎn)發(fā)成功。
call3(f, std::move(0)); //類型參數(shù)推斷為具名int &&,轉(zhuǎn)發(fā)時(shí)std::forward將具名int &&轉(zhuǎn)換為無名int &&,轉(zhuǎn)發(fā)成功。
return system("pause");
}