我試圖深入理解完美轉發,并面臨一個我自己無法弄清楚的問題。假設這段代碼:
void fun(int& i) {
std::cout << "int&" << std::endl;
}
void fun(int&& i) {
std::cout << "int&&" << std::endl;
}
template <typename T>
void wrapper(T&& i) {
fun(i);
}
int main()
{
wrapper(4);
}
它列印int&。要解決這個問題,應該使用 std::forward。這很清楚。不清楚的是為什么會這樣。上面的代碼展開為:
void fun(int & i)
{
std::operator<<(std::cout, "int&").operator<<(std::endl);
}
void fun(int && i)
{
std::operator<<(std::cout, "int&&").operator<<(std::endl);
}
template <typename T>
void wrapper(T&& i) {
fun(i);
}
/* First instantiated from: insights.cpp:21 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void wrapper<int>(int && i)
{
fun(i);
}
#endif
int main()
{
wrapper(4);
return 0;
}
所以i應該有右值型別int&&。問題是:為什么我需要 std::forward ,因為編譯器已經知道它i不是int&&但int&仍然呼叫fun(it&)?
uj5u.com熱心網友回復:
型別和值類別是不同的東西。
每個 C 運算式(帶有運算元的運算子、文字、變數名等)都有兩個獨立的屬性:型別和值類別。
i,變數的名稱,是一個左值運算式,即使變數的型別是右值參考。
以下運算式是左值運算式:
- 變數的名稱,... 即使變數的型別是右值參考,由其名稱組成的運算式也是左值運算式;
- ...
這就是為什么我們應該使用std::forward來保留轉發參考引數的原始值類別。
uj5u.com熱心網友回復:
為什么我需要
std::forward在這里,因為編譯器已經知道我int&&不是int&但仍然呼叫fun(it&)?
的型別i是int&&,但i它本身是一個左值。所以當你呼叫時fun(i),由于i它本身是一個左值,編譯器會選擇fun(int &).
如果要呼叫fun(int &&),可以使用std::move將其轉換為右值
fun(std::move(i));
uj5u.com熱心網友回復:
為什么我在這里需要 std::forward ,因為編譯器已經知道 i 是 int&& 不是 int& 但仍然呼叫 fun(it&)?
因為i當用作/在諸如呼叫之類的運算式中時,它fun(i)是一個左值。那是i當用作/在運算式中時的值類別是lvalue。因此呼叫fun(i)選擇了第一個多載( void fun(int&))。
另一方面,宣告的型別是i,int&&即對 的右值參考int。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/467054.html
