[英]What is the rationale behind the typeid operator ignoring cv-qualifiers
根據C ++語言標准(ISO / IEC 14882:2003中的§5.2.8),
左值表達式或作為typeid操作數的type-id的頂級cv限定符始終被忽略。
這個決定的理由是什么。 它在類型系統上打了一個洞,是違反直覺的。 const信息(或易失性部分)在編譯時是已知的,因此如果typeid僅考慮了cv限定詞,則不會有開銷。
盡管具有使用const
, volatile
和const volatile
變體(請參見[class.mfct.nonstatic]),類型D
, const D
, volatile D
和const volatile D
(對於某些非cv限定類型)重載非靜態成員函數的能力D
)並非無關; 該標准在[basic.type.qualifier]中指定,對於每種不符合cv的類型 ,該類型都有一個具有相同表示和對齊要求的不同const
限定, volatile
限定和const volatile
限定的“版本”。 如果D
和const D
可能彼此不相關(例如,通過具有不同的表示形式,存儲要求,或者在類的情況下,具有不同的成員),則很多語言都將崩潰。
例如,類型D&
的對象可以隱式轉換為const D&
, volatile D&
和const volatile D&
(請參見[conv.qual])。 但是,如果允許D
與const D
不相關,則此轉換將沒有意義。
還考慮一下標准中的許多地方指定了頂級cv限定詞將被忽略:
[over.load]指定:
僅在存在和不存在
const
和/或volatile
方面不同的參數聲明是等效的。 也就是說,在確定要聲明,定義或調用哪個函數時,將忽略每種參數類型的const
和volatile
類型說明符。
[temp.param]指定:
確定模板參數的類型時,將忽略模板參數上的頂級cv限定詞 。
[basic.life]在指定如何重用其生命周期結束的對象的存儲時,提到:
新對象與原始對象具有相同的類型(忽略頂級cv限定詞)
[over.best.ics]指定:
頂級簡歷的任何差異都歸因於初始化本身,並不構成轉換。 [ 示例:類型
A
的參數可以從類型const A
的參數初始化。 在這種情況下,隱式轉換序列是標識序列。 它不包含從const A
到A
“轉換”。 ]
[temp.deduct.call]指定:
如果
A
是CV-限定的類型,頂層cv修飾符A
的類型被忽略類型推演。
和:
如果
P
是CV-限定的類型,頂層cv修飾符P
的類型被忽略類型推演。
([temp.deduct.conv]使用類似的語言。)
[except.throw]指定:
throw-expression會初始化一個臨時對象,該臨時對象的類型是通過從
throw
操作數的靜態類型中刪除所有頂級cv限定符並將“T
數組”或“返回T
函數”的類型調整為“指向T
指針”或“返回T
函數的指針”。
[except.handle]指定:
處理程序是類型為
E
的對象的throw-expression的匹配項,如果—處理程序的類型為cv
T
或cvT&
而E
和T
是同一類型(忽略頂級cv限定詞),或…
如果允許D
, const D
, volatile D
和const volatile D
是不相關的類型,則所有這些都必須更改。
因為如果操作數是多態對象,則typeid
返回動態類型。 Cv限定詞被設計為編譯時限制,並且必須在運行時記錄其他信息才能檢索動態類型的cv限定詞,因此可以忽略頂級cv限定詞。
對於類型或非多態對象的操作數, typeid
忽略頂級cv限定詞以保持一致性。 否則,例如,以下assert
將意外觸發:
struct Base {
virtual ~Base() {}
};
struct Derived : public Base {};
const Derived *d = new Derived;
const Base *b = d;
assert(typeid(*b) == typeid(decltype(*d))); // should not fire
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.