template<typename F,typename T1,typename T2>
void myfunctemp(F f, T1 &&t1, T2 &&t2) //類模板函式,萬能參考作為模板函式形參,既能接收左值,又能接收右值。
{
f(t1, t2);
}
void myfunc(int &&v1, int &v2)
{
cout << v1 << endl;
cout << v2 << endl;
}
void func(int a){cout << a << endl;} //普通函式
int main()
{
int i = 8; //左值
myfunctemp(myfunc, 30, i); //右值30傳給萬能參考形參t1,但函式體內f函式形參t1為左值,編譯不通過??①此處為什么就不行呢
func(i); //普通函式func形參a為左值,故可接收實參i(左值);
func(99); //普通函式func形參a為左值,但卻可以接收實參99(右值);??②
return 0;
}
上面標示??①和??②的地方比較疑惑,因為①處用函式模板將形參30和i轉發給函式f時,t1(左值)不能接收右值(30)。編譯不能通過,編譯器報錯不能將右值系結到左值。但是在普通函式②處為什么就可以直接將右值99傳給左值形參a呢?求大神們給解惑?下面是編譯結果

uj5u.com熱心網友回復:
template<typename F,typename T1,typename T2>
template<typename F, typename T1, typename T2>
void myfunctemp(F f, T1 &&t1, T2 &&t2) //類模板函式,萬能參考作為模板函式形參,既能接收左值,又能接收右值。
{
f(std::forward<T1>(t1), std::forward<T2>(t2));
}
t1和t2在myfunctemp函式中傳給f的時候具名了,退化成了左值,應該用std::forward轉發
uj5u.com熱心網友回復:
這樣看應當就明白了。
#include <iostream>
using namespace std;
void func0(int a)
{
cout << a << endl;
} //普通函式
void func1(int &a)
{
cout << a << endl;
} //普通函式
void func2(const int &a)
{
cout << a << endl;
} //普通函式
int main()
{
int i = 8; //左值
func0(i);
func0(99);
func1(i);
func1(99);
func2(i);
func2(99);
return 0;
}
uj5u.com熱心網友回復:
因為myfunctemp(myfunc, 30, i); 特化時候原型是myfunctemp<void (*)(int &&, int &), int, int &>
而不是你想象的
myfunctemp<void (*)(int &&, int &), int &&, int &>
uj5u.com熱心網友回復:
我知道具名后t1代表左值,那能將整個(&&t1)作為f函式的形參來接收右值嗎?
還有像void func(int a){cout << a << endl;} 這個普通函式,如果直接在主函式中呼叫傳進去一個const右值。func(100);為什么就可以呢?形參a不是左值型別嗎,100不是右值型別嗎,為什么就可以接收正常輸出呢?
uj5u.com熱心網友回復:
理解一下這個代碼,估計你會明白int&& r1=10;//正確
int&& r2=r1;//錯誤
當你使用一個右值參考只能去系結一個臨時值,而不能系結一個已存在的值,
再給你一個代碼
#include <iostream>
using namespace std;
void RunCode(int&& m) {
cout << "right call" << endl;
}
void RunCode(int& m) {
m++;
cout << "left call" << endl;
}
int main()
{
int&& b = 10;
RunCode(10);//呼叫了RunCode(int&&);
RunCode(b);//呼叫了RunCode(int&);
return 0;
}
uj5u.com熱心網友回復:
再去理解一下c++參考折疊就清楚了uj5u.com熱心網友回復:
還有一個普通函式接受右值,你的理解還是有偏差,所謂的參考則是為了減少拷貝次數引入的,當一個函式的引數是參考(無論左右),它都會直接把實參本身傳遞給函式(一般通過指標),而你舉的例子,那個引數只是個值型別(int),無論你傳左值還是右值都會發生復制。也就是說在函式內部,對引數修改不會影響到呼叫方。uj5u.com熱心網友回復:
參考折疊跟這個有什么關系呢,參考折疊不是在系統內部實作的嗎。uj5u.com熱心網友回復:
完美轉發就是使用的參考折疊規則啊uj5u.com熱心網友回復:
void func (int a){cout<<a<<endl;}
主函式中呼叫func函式:i=100;func(i);//成立
func(88); //成立
上面這段代碼用參考折疊是不是可以這樣認為:當傳入實參i時,因為實參i為左值。所以a可以直接接收i值。
當傳入右值88時,實際是將88傳給系統推斷的func函式原型void func(int int&&)右側的int&&來接收,而(int int&&)前面為左值,后面為右值,通過折疊規則:有左值結果即為左值。是不是(int int&&)整體是不是就成了一個左值?
uj5u.com熱心網友回復:
fun(int a) 這個a不是參考,無論你傳左值還是右值,都是先復制到a然后再運算,與你的問題無關uj5u.com熱心網友回復:
大神,你這段代碼的意思是如果我們隨便呼叫一個普通函式,如void func(int a){....};不管實參給的是變數左值還是常量右值,系統都可以編譯通過,是因為C++內部對函式func進行了多載嗎?func(int &);func(int &&)
uj5u.com熱心網友回復:
func1(99);這個編譯不通過是因為99是右值,而void func1(int &a) 接收到的是一個左值參考。但是func0(99)為什么就能編譯通過呢,形參a不是一個左值嗎,而實參99不是右值嗎,為什么就能編譯通過呢?
uj5u.com熱心網友回復:
大神,你的意思左值,右值只是針對參考嗎?
uj5u.com熱心網友回復:
不是只能針對參考,而是只有參考才能表現你的問題。而作為普通引數,你無論傳入左值還是右值,都需要復制。所以不能體現你的問題。
uj5u.com熱心網友回復:
void fun(int m){m++;
}
void fun1(int &m){
m++;
}
...
int b=10;
fun(b);
fun1(b);
理解一下上述代碼
參考及別名,參考及他所系結的變數,而值型別引數,傳入后,就是兩個不同變數,不能互相影響。
uj5u.com熱心網友回復:
這樣看應當就明白了。
#include <iostream>
using namespace std;
void func0(int a)
{
cout << a << endl;
} //普通函式
void func1(int &a)
{
cout << a << endl;
} //普通函式
void func2(const int &a)
{
cout << a << endl;
} //普通函式
int main()
{
int i = 8; //左值
func0(i);
func0(99);
func1(i);
func1(99);
func2(i);
func2(99);
return 0;
}
func1(99);這個編譯不通過是因為99是右值,而void func1(int &a) 接收到的是一個左值參考。但是func0(99)為什么就能編譯通過呢,形參a不是一個左值嗎,而實參99不是右值嗎,為什么就能編譯通過呢?
因為形參a,不是實參,好吧,這是廢話。
fun0,的函式呼叫程序相當于賦值。(實際上是有區別的),所以,變數常量都可以傳遞進去。
fun1,的引數是參考,99是常量,但參考的型別不是常量的參考,而是變數參考(99是立即數,是常量),所以無法編譯通過。所以只能傳遞變數,無法傳遞常量(立即數)。
fun2,的引數是參考(常量參考,不會改變參考的值),所以可以傳遞變數(不會改變傳進去參考的值,傳變數過去也沒問題)和常量進去。
uj5u.com熱心網友回復:
為什么就可以直接將右值99傳給左值形參a呢?
你這是什么意思?當然是可以的啊,所以你認為 int a = 1; 是非法的嗎?。。。
值是值,是運算式的結果
參考是參考,是一種型別(就像char、short、int等一樣,都是型別)
不要搞混!
比如: int&& i中,i的型別是右值參考型別,但i的值類別(i這個運算式)是左值。
參考不可能單獨存在,它不占物理空間,所以它所謂的實體化時,必須所謂的“系結”到一個值上(成為這個值的別名)。
而值類別有兩種:左值和右值
所以參考就有左值參考和右值參考
呼叫函式時,只要實參運算式的型別符合形參的型別或者可以轉換成形參的型別那就是符合語法的。
那所謂的“符合”是什么呢?基本型別就不用說了吧?但是當形參型別是 xx參考 時呢?
由于參考可以“系結”到一個值上,所以就肯定有額外的符合情況 :
在型別相符的前提下,實參運算式結果的值類別可以被系結到該參考上即可。
算上const的話,參考型別有:Type& 、 const Type& 、 Type&& 、 const Type&&(暫無用途)
而值類別有:非常量左值、 常量左值、 非常量右值、常量右值
怎樣的參考可以系結到怎樣的值類別呢:
Type& 只能系結到 非常量左值
const Type& 可以系結到非常量左值、 常量左值、 非常量右值、常量右值。 (都可以系結)
Type&& 只能系結到非常量右值
const Type&& 只能系結到非常量右值、常量右值
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/221243.html
標籤:C++ 語言
上一篇:初學者關于亂數統計結果的的問題
