typeid 运算符忽略 cv 限定符背后的理由是什么?
What is the rationale behind the typeid operator ignoring cv-qualifiers
摘自 ISO/IEC 14882:2003 的 C++ 语言标准 §5.2.8,引用,
始终忽略左值表达式的顶级 cv 限定符或作为 typeid 的操作数的类型 id。
做出这一决定的理由是什么。它在类型系统上打了一个洞,是违反直觉的。常量信息(或易失部分)在编译时是已知的,因此如果typeid只考虑cv限定符,则不会产生开销。
尽管能够重载具有const
、volatile
和const volatile
变体的非静态成员函数(参见[class.mfct.nonstatic]),但类型D
、const D
、volatile D
和const volatile D
(对于某些非CV限定的类型D
)并非无关;该标准在[basic.type.qualifier]中指定,对于每个cv-nonqualible类型,每个cv-nonqualible类型。,则存在具有相同表示和对齐要求的类型的不同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] 指定:
顶级简历资格的任何差异都包含在初始化本身中,不构成转换。[示例:可以从类型为
const A
的参数初始化类型A
的参数。这种情况的隐式转换序列是标识序列;它不包含从const A
到A
的"转换"。] -
[temp.deduct.call] 指定:
如果
A
是符合 cv 条件的类型,则忽略A
类型的顶级 cv 限定符以进行类型推断。和:
如果
P
是符合 cv 条件的类型,则忽略P
类型的顶级 cv 限定符以进行类型推断。([temp.deduct.conv] 也有类似的语言。
-
[除了投掷] 指定:
throw-expression初始化一个临时对象,其类型是通过从
throw
的操作数的静态类型中删除任何顶级cv 限定符并确定类型分别从"T
数组"或"函数返回T
"调整为"指向T
的指针"或"指向返回T
的函数的指针"来确定的。 -
[例外句柄] 指定:
处理程序是具有
E
类型的对象的抛出表达式的匹配项,如果— 处理程序的类型为 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
- 有充分的理由在h文件中使用include保护而不是cpp文件吗
- "std::unique_XXX"命名约定背后的基本原理是什么?
- 共享指针和具有自定义删除程序的唯一指针之间的语法差异背后的任何原因
- std::背后的基本原理assignable_from可能的实现
- 传递背后的原因 通过引用C++中的函数?
- 在调用其析构函数之前,是否有任何实际理由检查某些东西是否可破坏?
- 无法理解代码背后的逻辑,这是在两个给定数字之间生成素数的优化问题
- 嵌套循环背后的逻辑
- std::set<Key,Compare,Allocator>::find() 函数使用"<"运算符而不是"=="运算符背后的直觉是什么?
- 有什么理由不扩展 std::set 以添加下标运算符吗?
- while(sline >> n >> c && c== ',')背后的逻辑是什么?
- 是否有理由在标题中保留完全专用的模板?
- 全局和局部变量初始化与 constexpr 的差异背后的基本原理
- 不允许功能模板的部分专业化背后的理由是什么?
- typeid 运算符忽略 cv 限定符背后的理由是什么?
- 对于类型是类模板专业化的参数,ADL背后的理由是什么
- 当编译器看到 std::vector<Typo> 和 std::vector<struct 拼写错误时发出的诊断之间的差异背后的理由是什么>
- 工会活跃成员背后的理由
- "inline function need to be DEFINED in all tranlation units"背后的理由是什么?
- 可恢复功能限制背后的理由