以下是我曾尝试解决此问题的一些CRTP based template code:Requiring 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
的任何人来说都是灾难,但为什么会出现这种不一致在typedef
和typeid
之间?
编辑:GCC接受typedef
变量声明。最后,类型只是TDerived04::TDerived04::TDerived04::TDerived04 lD4;
。是否存在折叠范围解析的规则?显然,MSVC ++和GCC似乎都在TDerived04
中做同样的事情,但是与GCC不同,MSVC ++无法处理其他场景 - 它会产生编译错误,需要构造函数的参数。
答案 0 :(得分:1)
问题大致是注入的类名和构造函数名之间存在歧义。在class X
的范围内,X
可以为类本身命名,但X::X
也可以引用构造函数 - 哪里有意义。
答案 1 :(得分:1)
我不会考虑将typeid
用作调试工具之外的其他内容。 C ++标准只保证它的存在,但并没有真正说它应该做什么。这使得这种优点只不过是一种打印人类可读类名的方法(如果你知道其他任何实际用途,请纠正我)。
我想说typeid
有太多“编译器定义”行为,使其对上述任何其他内容都有用。
解决方案中提出的方法也有很大的缺点。除了丑陋和难以维护之外,基类还需要了解所有派生类。这是一个相当大的设计缺陷。
至于替代解决方案,可以看到here(代码也发布在原始问题中)。
至于有效的TDerived04::TDerived04::TDerived04::TDerived04
,可以通过TDerived04类中的那个来解开,你可以使用它的名称TDerived04来引用这个类/命名空间。所以TDerived04 :: TDerived04就像从TDerived04那样指向TDerived04类(因为@MSalters说它被称为“类名注入”)。