编译器如何评估`typeid`运算符?

时间:2012-01-03 10:54:34

标签: c++ templates compiler-construction crtp typeid

以下是我曾尝试解决此问题的一些CRTP based template codeRequiring overridden virtual functions to call base implementations。我会在这里发布代码,但是这些行很长很容易在codepad.org上阅读(如果需要我会在这里发布)。它很丑陋,当然有点人为,虽然它确实有效。但是我一开始并没有意识到,虽然它在MSVC ++和GCC上编译,但是某些模板类型并没有真正定义。我在问题的部分是if( typeid( Derived(N) ) != typeid( Derived(N-1))函数顶部的几个长内TBase::OnEvent(符号表示法)。

你不能typdef这些类型,这将是一个编译错误 - 没有足够的派生类可以用如此长的...::TDerived::...链定义类型,所以你得到了,正确地,编译错误TDerived is not defined in TBase。然而编译器通过typeid来吃掉它们。当我检查调试器MSVC ++编译器输出(带有完整的符号信息)时,似乎所有那些不应该真正导致任何类的长...::TDerived::...typeid由编译器解析为仅仅是最后一个{{ 1}}在类链中。 RTTI是为类链中的最后一个类提取的,与我有多少TDerived04无关。

考虑到MSVC ++和GCC都这样做(尽管我只能通过codepad.org访问GCC),我的问题是下一个:它是否以某种方式定义了...::TDerived::...的行为?为什么那些长typeid中的任何一个typedef都无法解析为...::TDerived::...

编辑:我的意思是,我很高兴TDerived04无法解析为typedef,对于使用TDerived04的任何人来说都是灾难,但为什么会出现这种不一致在typedeftypeid之间?

编辑:GCC接受typedef变量声明。最后,类型只是TDerived04::TDerived04::TDerived04::TDerived04 lD4;。是否存在折叠范围解析的规则?显然,MSVC ++和GCC似乎都在TDerived04中做同样的事情,但是与GCC不同,MSVC ++无法处理其他场景 - 它会产生编译错误,需要构造函数的参数。

2 个答案:

答案 0 :(得分:1)

问题大致是注入的类名和构造函数名之间存在歧义。在class X的范围内,X可以为类本身命名,但X::X也可以引用构造函数 - 哪里有意义

答案 1 :(得分:1)

我不会考虑将typeid用作调试工具之外的其他内容。 C ++标准只保证它的存在,但并没有真正说它应该做什么。这使得这种优点只不过是一种打印人类可读类名的方法(如果你知道其他任何实际用途,请纠正我)。

我想说typeid有太多“编译器定义”行为,使其对上述任何其他内容都有用。

解决方案中提出的方法也有很大的缺点。除了丑陋和难以维护之外,基类还需要了解所有派生类。这是一个相当大的设计缺陷。

至于替代解决方案,可以看到here(代码也发布在原始问题中)。

至于有效的TDerived04::TDerived04::TDerived04::TDerived04,可以通过TDerived04类中的那个来解开,你可以使用它的名称TDerived04来引用这个类/命名空间。所以TDerived04 :: TDerived04就像从TDerived04那样指向TDerived04类(因为@MSalters说它被称为“类名注入”)。