我試圖了解如何參考初始化。例如,讓我們看一個典型的例子。
double val = 4.55;
const int &ref = val;
我可以想到上面代碼片段中發生的兩種可能性。
可能性 1
通常的解釋如下:
這里創建了一個帶值型別的臨時( prvalue ),然后將參考系結到這個臨時(prvalue)物件,而不是直接系結到變數。發生這種情況是因為右側變數的型別是在左側我們有一個參考。但是對于系結對變數的參考,型別應該匹配。此外,延長了臨時純右值的生命周期。int4refintvalvaldoubleint
可能性 2
我認為還有另一種可能發生,如下所示:
這里創建了一個帶有值的臨時(prvalue)型別。但是由于需要一個glvalue并且目前我們有一個prvalue,臨時物化開始了,所以 prvalue 被轉換為一個xvalue。然后將參考系結到這個具體化的 xvalue(因為 xvalue 也是一個 glvalue) ,而不是直接系結到變數。發生這種情況是因為右側變數的型別是在左側我們有一個參考。但是對于系結對變數的參考,型別應該匹配int4const int &refrefvalvaldoubleint. 此外,物化的臨時 xvalue 的生命周期得到了延長。
我的問題是:
- 根據 C 11 標準,以上哪個解釋是正確的。我愿意接受上述解釋都不正確,在這種情況下,正確的解釋是什么。
- 根據 C 17 標準,以上哪個解釋是正確的。我愿意接受上述解釋都不正確,在這種情況下,正確的解釋是什么。
- 我也很困惑上述兩種可能性的第一步中的prvalue是否實際上是一個臨時物件?或者 xvalue 是實際物件。我的意思是我們有 2 個臨時物件,比如第一個是由于“轉換為純右值”,第二個是由于“純右值到 xvalue”轉換(臨時物化)。還是我們只有一個臨時的,這是由于“prvalue to xvalue”臨時實作。
PS:我不是在尋找解決這個問題的方法。例如,我知道我可以簡單地寫:
const double &ref = val;。我的目標是根據C 11和C 17標準了解正在發生的事情。
uj5u.com熱心網友回復:
valinconst int &ref = val;是左值,而不是純右值。即使它被轉換為純右值,這并不意味著在 C 11 或 C 17 中創建一個臨時值。在 C 17 中,情況并非如此,因為只有純右值到極值的轉換(以及一些與此無關的特殊情況)會創建一個臨時值,而在 C 11 [conv.lval]/2中表示僅適用于型別別左值到右值的轉換創建一個臨時的。
在 [dcl.init.ref] 中解釋了參考的初始化。
在 C 11 中,所有以前的情況都失敗了,因此根據[dcl.init.ref]/5.2.2,目標型別的臨時物件通過初始化運算式的復制初始化創建和初始化,并且參考系結到那個暫時的。在此復制初始化中,左值val被轉換為型別的純右值double,然后轉換為型別的純右值int,這些步驟都不會創建額外的臨時值。
在 C 17 中,所有情況都一直持續到[dcl.init.ref]/5.2.2,它指出初始化運算式首先被隱式轉換為目標型別的純右值,這并不意味著創建一個臨時值,然后應用臨時實作轉換(prvalue-to-xvalue 轉換)并將參考系結到結果,即參考臨時的xvalue。
最終總會有一個臨時的,即根據 [dcl.init.ref] 中的規則創建的那個。
uj5u.com熱心網友回復:
讓我們分別看一下每種情況(C 11 vs C 17)。
C 11
從decl.init.ref 5.2.2:
否則,將使用非參考復制初始化 ([dcl.init]) 的規則從初始化運算式創建并初始化“cv1 T1”型別的臨時變數。然后將參考系結到臨時檔案。
需要注意的另一件事是basic.lval#4:
類純右值可以有 cv 限定型別;非類純右值總是有 cv 非限定型別...
當應用于您的示例時,這意味著創建一個臨時型別,并使用非參考復制初始化規則int從初始化運算式初始化。如果/當用作運算式時,如此創建val的臨時值具有prvalueint的值類別。
接下來,參考ref然后系結到臨時int創建的具有 value 4。因此,
double val = 4.55;
const int &ref = val; // ref refers to temporary with value 4
C 17
從decl.init.ref 5.2.2.2:
否則,初始化運算式被隱式轉換為“cv1 T1”型別的純右值。應用臨時實作轉換并將參考系結到結果。
當應用于您的示例時,這意味著初始化運算式val被隱式轉換為型別的純右值const int。現在我們現在有一個prvalue const int。但在應用臨時實作之前,expr 6開始執行,其中說:
如果prvalue最初具有型別“cv T”,其中
T是cv-unqualified non-class,non-array型別,則在進一步分析之前將運算式的型別調整為T。
這意味著在臨時實作之前,prvalueconst int被調整為 prvalue int。
最后,應用臨時物化,并ref系結到結果xvalue。
uj5u.com熱心網友回復:
這是我對 C 17 的看法:
double val = 4.55;
const int &ref = val;
我們正在系結對由 表示const int的型別的左值運算式的參考。根據參考的宣告;doubleval
否則,初始化運算式被隱式轉換為“T1”型別的純右值。
我們將運算式轉換val為 type int。注意這個隱式型別!轉換符合草案。下一個,
考慮到prvalue的型別為“cv1 T1”,應用臨時實作轉換,...
為了應用臨時實作(也稱為 prvalue -> xvalue 轉換),我們必須具有完全匹配的型別,因此運算式被額外轉換為被認為const intconst int沒有任何轉換(source)。值類別保持不變(prvalue)。最后,
...并且參考系結到結果。
我們有一個型別的參考系結T到一個型別的純右值,T它會導致臨時實作(源)并val轉換為 xvalue。創建的臨時物件的型別const int和值是4。
編輯:當然要回答你的問題。因此,從一開始,對于 C 17 來說,給定的可能性在技術上都不是正確的。嚴格來說,prvalues 和 xvalues 都不是臨時物件。相反,它們是運算式的值類別,運算式可能(或可能不)表示(臨時)物件。所以從技術上講,xvalues 表示臨時物件,而 prvalues 不表示。你仍然可以說 xvalues 是臨時物件,只要你知道你在說什么,我完全沒問題。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/464687.html
下一篇:如何使用演繹法選擇函式的回傳型別
