typeid运算符忽略cv-qualifiers背后的基本原理是什么?

时间:2018-02-10 05:14:23

标签: c++ typeid typeinfo

来自C ++语言标准,来自ISO / IEC 14882:2003的§5.2.8,引用,

  

总是忽略左值表达式的顶级cv限定符或作为typeid操作数的type-id。

这个决定的理由是什么?它在类型系统中打了一个洞,反直觉。 const信息(或易失性部分)在编译时是已知的,因此如果typeid只考虑了cv限定符,就没有开销。

2 个答案:

答案 0 :(得分:2)

尽管能够使用constvolatileconst volatile变体(请参阅[class.mfct.nonstatic])重载非静态成员函数,但请键入D,{ {1}},const Dvolatile D(对于某些非cv限定类型const volatile D)并不相关;标准在[basic.type.qualifier]中指定,对于每个 cv-unqualified type ,有一个不同的D - 限定的,const - 限定的,{{1 } - - 合格"版本"具有相同表示和对齐要求的类型。如果volatileconst volatile可能彼此无关(例如,通过具有不同的表示,存储要求,或者在类,不同成员的情况下),那么很多语言都会打破了。

例如,D类型的对象可隐式转换为const DD&const D&(请参阅[conv.qual])。但是,如果允许volatile D&const volatile D&无关,则此转换无效。

还要考虑标准中的许多地方指定忽略顶级cv限定符:

  • [over.load]指定:

      

    仅在D和/或const D存在或不存在时不同的参数声明是等效的。也就是说,在确定声明,定义或调用哪个函数时,将忽略每个参数类型的constvolatile类型说明符。

  • [temp.param]指定:

      

    模板参数上的顶级 cv-qualifiers 在确定其类型时会被忽略。

  • [basic.life],在指定如何重复使用其生命周期结束的对象的存储时,请注意:

      

    新对象与原始对象的类型相同(忽略顶级cv限定符)

  • [over.best.ics]指定:

      

    顶级cv资格的任何差异都归入初始化本身,并不构成转换。 [示例:类型const的参数可以从类型volatile的参数初始化。该情况的隐式转换序列是标识序列;它不包含从Aconst A的“转化”。 ]

  • [temp.deduct.call]指定:

      

    如果const A是cv限定类型,则类型扣除将忽略A类型的顶级cv限定符。

      

    如果A是cv限定类型,则类型扣除将忽略A类型的顶级cv限定符。

    ([temp.deduct.conv]有类似的语言。)

  • [except.throw]指定:

      

    throw-expression 初始化一个临时对象,其类型是通过从{的操作数的静态类型中删除任何顶级 cv-qualifiers 来确定的。 {1}}并将类型从“P数组”或“返回P的函数”调整为“指向throw的指针”或“返回T的函数指针”分别。

  • [except.handle]指定:

      

    处理程序 throw-expression T类型对象的匹配,如果

         

    - 处理程序的类型为 cv T cv T,而ET是相同类型(忽略顶级cv限定符),或......

如果T&ETD被允许为不相关的类型,则必须更改所有这些内容。

答案 1 :(得分:1)

因为如果操作数是polymorphic objecttypeid会返回动态类型。 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