[英]Cv-qualifications of prvalues (revisited)
這是我之前的問題的后續問題,其中明顯的共識是,prvalues 的 cv-qualifications 處理的變化只是一個相當小的和無關緊要的變化,旨在解決一些不一致的問題(例如,返回 prvalues 並聲明為 cv-qualified return 的函數類型)。
但是,我在標准中看到另一個地方似乎依賴於具有 cv 限定類型的純右值:通過臨時實現轉換使用純右值初始化const
引用。 相關措辭可在9.3.3/5的多個位置找到
[...] 如果轉換后的初始值設定項是純右值,則其類型 T4 調整為類型“cv1 T4” ([conv.qual]) 並應用臨時實現轉換 ([conv.rval]) [...]
[...] 否則,初始化表達式被隱式轉換為“cv1 T1”類型的純右值。 應用臨時實現轉換並將引用綁定到結果。
目的顯然是為了確保當我們進行實際的臨時物化轉換時
7.3.4 臨時實現轉換
1 T 類型的純右值可以轉換為 T 類型的 xvalue。此轉換通過使用臨時 object 作為其結果 ZA8CFDE63311C49EB66 評估純右值,從純右值初始化 T 類型的臨時 object ([class.temporary]) 並產生一個表示臨時 object 的 xvalue。 [...]
它作為輸入接收的類型T
包括所需的 cv 限定。
但是,在非類非數組純右值的情況下,該 cv-qualification 如何在7.2.2/2中存活下來?
7.2.2 類型
2如果純右值最初具有類型“cv T”,其中 T 是無 cv 限定的非類、非數組類型,則表達式的類型在任何進一步分析之前調整為 T。
或者是嗎?
例如,在這個例子中我們得到什么樣的臨時
const int &r = 42;
是否是臨時const
? 我們能做到嗎
const_cast<int &>(r) = 101; // Undefined or not?
不觸發未定義的行為? 如果我沒記錯的話,最初的意圖是在這種情況下臨時獲得一個const int
。 還是真的嗎? (對於 class 類型,答案很明確 - 我們得到一個const
臨時變量。)
對於
const int& r1=42
引用的類型為const int
,因此cv1為const
,而prvalue的類型為const int
,因此物化臨時類型也為const int
。
例如,在這個例子中我們得到什么樣的臨時
const int &r = 42;
是否是臨時常量?
讓我們分析您的示例,看看它是否為 const 。 鑒於這個例子
const int& r = 42;
標准的適用措辭是[dcl.init.ref]/5
對“
cv1 T1
”類型的引用由“cv2 T2
”類型的表達式初始化,如下所示:
- (5.1) [..]
- (5.2) [..]
- (5.3)否則,如果初始化表達式
- (5.3.1)是右值(但不是位域)或 function 左值,“
cv1 T1
”與“cv2 T2
”引用兼容,或- (5.3.2) [..]
那么第一種情況下的初始化表達式
的值和第二種情況下的轉換結果稱為轉換后的初始化程序。 如果轉換后的初始值設定項是純右值,則將其類型 T4 調整為類型“cv1 T4” ([conv.qual]) 並應用臨時實現轉換 ([conv.rval])。 在任何情況下,引用都綁定到生成的 glvalue (或適當的基礎 class 子對象)。
已經知道初始化表達式42
是純右值,並且const int
( cv1 T1
) 與int
( cv2 T2
) 是引用兼容的。 並且這里轉換的初始化程序是int
( T4
) 類型; 然后通過[conv.qual]將其調整為const int
( cv1 T4
); 然后應用臨時實現( [conv.rval] )。 但在應用它之前, [expr.type]/2開始:
如果prvalue最初具有類型“
cv T
”,其中T
是無cv限定的非類、非數組類型,則表達式的類型在任何進一步分析之前調整為T
這里的進一步分析包括臨時實現轉換。
所以調整后的純右值的類型是int
而不是const int
。 此時可以輸入[conv.rval] :
T
T
的 xvalue。 此轉換初始化 T 類型的臨時 object ([class.temporary]) [..]
所以你有一個 xvalue 表示一個臨時類型的int
。 並且引用r
綁定到生成的 glvalue (即, r
綁定到表示臨時類型int
而不是const int
的 xvalue)。
據我所知,已創建的臨時不是const-qualified 。
你為什么懷疑7.2.2的語言? 在非類、非數組純右值上丟棄 cv 限定符似乎非常明確,因此臨時物化中的類型 T 是非常量、非易失性類型。
如果不是這種情況,那么您將無法將純右值綁定到非常量右值引用。 然而,該標准似乎極有可能接受這樣的程序:
#include <type_traits>
template<typename T> void
f(T &&t)
{
static_assert(std::is_same_v<decltype(t), int&&>);
++t;
}
int
main()
{
f(5);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.