我使用auto
的一些情況:汽車演繹類型如何?
auto s = expr; //s is always lvalue
auto & s = expr; //s is always lvalue reference? What if expr is rvalue?
auto && s = expr; //s is perfectly forwarded
他們是真的嗎?如果不是,爲什麼?
我使用auto
的一些情況:汽車演繹類型如何?
auto s = expr; //s is always lvalue
auto & s = expr; //s is always lvalue reference? What if expr is rvalue?
auto && s = expr; //s is perfectly forwarded
他們是真的嗎?如果不是,爲什麼?
dyp是正確的,我想詳細說明。
首先,得出的結論是從DYP:
在一個變量聲明爲推導出的
auto
類型經由模板參數推導規則定義 ,見[dcl.spec.auto ]/6; 但有一個例外:如果初始化程序是一個加載初始化列表,則 推導的類型是std::initializer_list
。
我會解釋一下。
首先,
auto s = expr;
這是一樣的推斷來自expr
的T
,
template<class T>
void f(T s);
f(expr);
模板參數推導規則是相當複雜的,因爲你只用左值和右值有關東西,讓我們專注於此。
模板參數推導是通過(在這種情況下是P
T
稱之爲P
,)模板參數類型進行比較,以及相應的參數(稱之爲A
,在這種情況下,expr
類型)。
從14.8.2.1,
如果P不是引用類型:
- 如果A是一個數組類型,由陣列到指針標準轉換所產生的指針類型(4.2 )是 用於代替A的類型扣除;否則,
- 如果A是一個函數類型,則由函數指針標準轉換生成的指針類型(4。3)用 代替A進行類型扣除;否則,
- 如果A是cv限定類型,則A類型的頂級cv限定符在類型推導中將被忽略。
所以,如果expr
是陣列或功能,這將被視爲指針,如果expr具有cv-限定符(const
等),它們將被忽略。
如果
P
是CV-限定的類型,P
的類型的頂層cv修飾符被忽略類型推演。
這實際上說:
const auto s = expr;
s
是const
變量,但類型扣除auto
目的,const
將被刪除。
因此,從上述規則,auto
將被推斷爲類型expr
(經過上述一些類型轉換後)。
請注意,當表達式是對T
的引用時,在事先分析之前它將被調整爲T
。
因此無論expr
是 - 右值,左值還是右值/右值ref類型 - auto
的類型將始終爲expr
的類型,而不帶參考。
auto s1 = 1; //int
int &x = s1;
auto s2 = x; //int
int &&y = 2;
auto s3 = y; //int
其次,讓我們來看看
auto &s = expr;
這將是相同
template<class T>
void f(T &s);
f(expr);
從標準的額外的規則如下:
如果
P
是參考類型,由引用用於類型扣除。
所以汽車的扣將作爲無&
完全相同,但扣除auto
類型後,&
被添加到auto
末。
//auto &s1 = 1; //auto is deducted to int, int &s1 = 1, error!
const auto &s1 = 1; //auto is deducted to int, const int &s1 = 1; ok!
const int &x = s1;
auto &s2 = x; //auto is int, int &s2 = x; ok!
int &&y = 2;
auto &s3 = y; //auto is int, int &s3 = y; ok!
請注意,最後的y
是一個左值。 C++的規則是:名稱右值引用是一個左值。
最後:
auto &&s = expr;
這是毫無疑問的一樣
template<class T>
void f(T &&s);
f(expr);
一個從標準的附加規則:
如果
P
是一個右值引用的cv-不合格模板參數和 參數是一個左值,類型「左值參考A」是用於 的地方A
進行類型扣除。
這實際上說,如果expr
是一個rvalue,該規則將是相同於該第二殼體(左值的情況下),但如果expr
是一個左值,的A
類型將是一個左值參考A
。
從前面解釋的注意,A
永遠不會引用,因爲表達式的類型永遠不會是引用。但對於這種特殊情況(auto &&
和A
是左值),必須使用對A
的引用,而不管expr
本身是否爲引用類型。
實施例:
auto &&s1 = 1; //auto is deducted to int, int &&s1 = 1, ok!
int x = 1;
auto &&s2 = x; //x is lvalue, so A is int &, auto is deducted to int &, int & &&s2 = x; ok!
int &&y = 2;
auto &&s3 = y; //y is lvalue, auto is int &, int & &&s3 = y; ok!
最後一點我被混淆了:'auto&= makeSomething();',用'sometype makeSomething();':如果'sometype'是非const non-ref,這會失敗,因爲'auto'被推斷到'sometype'和'sometype&= makeSomething();'試圖將一個prvalue綁定到一個左值ref。如果'sometype' const(無參考),但是非類非數組,常量將根據[expr]/6被丟棄,並且發生相同的情況。如果'sometype'是一個常量類類型('使用sometype = myclass const;'),那麼這會工作,因爲'auto'被推斷爲'sometype const'(和'sometype const&s = makeSomething();'是合法的) 。 – dyp
使用和typedef將不會定義新類型,您的示例將不合法,因爲auto會被推斷爲myclass,而不是某種類型。 – user534498
糟糕,這是一個錯字:)它應該是:如果'sometype'是一個const類型,例如''使用sometype = myclass const;',那麼這將工作,因爲'auto'被推斷爲'myclass const'(和'myclass const&s = makeSomething();'是合法的)。 (順便說一句:'sometype const'只是多餘的,等同於'sometype') – dyp
由於沒有人給出答案,我現在有點了解(感謝@dyp),我只是在回答自己的問題。指出錯誤,如果任何:
auto s = expr;
如果expr
是左值,prvalue,或任何參考,s
始終是一個左值和一個副本。
auto& s = expr;
如果expr
是左值,左值參考或右值引用,s
是左值參考。 如果expr
是預估價值,這是一個錯誤,並且不合法。
auto&& s = expr;
s
完美轉發(右值將成爲右值引用和摺疊)。
在一個變量聲明爲推導'auto'類型是通過模板參數推導規則定義,見[dcl.spec.auto]/6;但有一個例外:如果初始化器是一個braced-init-list,則推導的類型是一個'std :: initializer_list'。 – dyp
順便說一句,作爲表達式的's'總是*左值,因爲's'是一個標識符(並且不是枚舉符)。左值/右值是表達式的類別。 – dyp
P.S.這也是*斯科特邁耶的通用參考文章(http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers);) – dyp