亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

為什么使用std :: forward禁用模板自變量推導?

為什么使用std :: forward禁用模板自變量推導?

C++
慕的地8271018 2019-10-31 13:00:34
在VS2010中,std :: forward的定義如下:template<class _Ty> inline_Ty&& forward(typename identity<_Ty>::type& _Arg){   // forward _Arg, given explicitly specified type parameter    return ((_Ty&&)_Arg);}identity似乎僅用于禁用模板參數推導。在這種情況下有意禁用它有什么意義?
查看完整描述

3 回答

?
智慧大石

TA貢獻1946條經驗 獲得超3個贊

如果將對類型對象的右值引用傳遞給以X類型T&&為參數的模板函數,則模板參數推導將推導T為X。因此,該參數具有type X&&。如果函數參數是左值或const左值,則編譯器會推導其類型為該類型的左值引用或const左值引用。


如果std::forward使用模板參數推導:


由于objects with names are lvalues只有輸入參數是未命名的右值(例如或),std::forward才能正確轉換T&&為。在完美轉發的情況下,您傳遞給的是左值,因為它具有名稱。的類型將推導為左值引用或const左值引用。引用折疊規則將導致in std :: forward 中的in始終解析為左值引用或const左值引用。7func()argstd::forwardstd::forwardT&&static_cast<T&&>(arg)


例:


template<typename T>

T&& forward_with_deduction(T&& obj)

{

    return static_cast<T&&>(obj);

}


void test(int&){}

void test(const int&){}

void test(int&&){}


template<typename T>

void perfect_forwarder(T&& obj)

{

    test(forward_with_deduction(obj));

}


int main()

{

    int x;

    const int& y(x);

    int&& z = std::move(x);


    test(forward_with_deduction(7));    //  7 is an int&&, correctly calls test(int&&)

    test(forward_with_deduction(z));    //  z is treated as an int&, calls test(int&)


    //  All the below call test(int&) or test(const int&) because in perfect_forwarder 'obj' is treated as

    //  an int& or const int& (because it is named) so T in forward_with_deduction is deduced as int& 

    //  or const int&. The T&& in static_cast<T&&>(obj) then collapses to int& or const int& - which is not what 

    //  we want in the bottom two cases.

    perfect_forwarder(x);           

    perfect_forwarder(y);           

    perfect_forwarder(std::move(x));

    perfect_forwarder(std::move(y));

}


查看完整回答
反對 回復 2019-10-31
?
泛舟湖上清波郎朗

TA貢獻1818條經驗 獲得超3個贊

因為std::forward(expr)沒有用。它唯一能做的就是無操作,即完美地推論其論點并像身份函數一樣工作。替代方法是與相同std::move,但我們已經有了。換句話說,假設有可能,


template<typename Arg>

void generic_program(Arg&& arg)

{

    std::forward(arg);

}

std::forward(arg)在語義上等效于arg。另一方面,std::forward<Arg>(arg)在一般情況下,這不是禁忌。


因此,通過禁止std::forward(arg)它可以幫助捕獲程序員錯誤,并且由于的任何可能的使用std::forward(arg)都被代替了,因此我們什么也不會丟失arg。


我認為,如果我們專注于確切std::forward<Arg>(arg) 執行的事情,而不是std::forward(arg)會執行的事情,您會更好地理解(因為這是無趣的禁忌)。讓我們嘗試編寫一個完美地傳遞其參數的無操作函數模板。


template<typename NoopArg>

NoopArg&& noop(NoopArg&& arg)

{ return arg; }

這種幼稚的第一次嘗試不是很有效。如果我們調用,noop(0)則NoopArg推導為int。這意味著返回類型為int&&并且我們不能從表達式中綁定這樣的右值引用arg,即左值(它是參數的名稱)。如果然后嘗試:


template<typename NoopArg>

NoopArg&& noop(NoopArg&& arg)

{ return std::move(arg); }

然后int i = 0; noop(i);失敗。這次NoopArg被推導出為int&(引用折疊規則保證將int& &&折疊為int&),因此返回類型為int&,這一次我們不能從std::move(arg)作為xvalue 的表達式中綁定這種左值引用。


在像的完美轉發函數的上下文中noop,有時我們想移動,而其他時候我們不想要。知道是否應該移動的規則取決于Arg:如果不是左值引用類型,則意味著noop傳遞了右值。如果是左值引用類型,則表示noop已傳遞左值。因此std::forward<NoopArg>(arg),為了使功能模板做正確的事情,NoopArg是中的一個必要參數std::forward。沒有它,就沒有足夠的信息。這NoopArg是不是同一類型什么T的參數std::forward會在一般情況下推斷。


查看完整回答
反對 回復 2019-10-31
?
楊魅力

TA貢獻1811條經驗 獲得超6個贊

由于我們將變量傳遞給std::forward,T將被推導為左值引用類型,并且引用折疊規則將確保返回類型與該左值引用類型相同,因此該調用將為左值。同樣,std::forward(0)將是一個xvalue。因此,推論std::forward將完美地提出其論點,并且是一個無人問津。

查看完整回答
反對 回復 2019-10-31
  • 3 回答
  • 0 關注
  • 608 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號