【问题标题】:How does compiler evaluate `typeid` operator?编译器如何评估 `typeid` 运算符?
【发布时间】:2012-01-03 10:54:34
【问题描述】:

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

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

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

编辑:我的意思是,我很高兴typedef 不能解析为TDerived04,这对于使用typedef 的任何人来说都是一场灾难,但是为什么typeidtypedef 之间存在这种不一致呢?

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

【问题讨论】:

  • 快速浏览一下代码后,您似乎正在尝试“重新实现”虚函数。还是我错过了什么?
  • @elmo 好吧,CRTP 允许实现某种“编译器时解析的虚拟机制”。我确实在回答与虚拟功能相关的问题。具体来说,在 base-derived00-derived01...-derivedLast 链中实现对中间类中所有函数的调用,而不在任何这些类中指定实际函数调用(如果感兴趣,请参阅原始问题)......但这不是这里的问题,这只是框架。我想知道typeid 的行为。
  • this 能解决您的问题吗?一般来说,我会考虑仅将 typeid 用于打印以进行调试。
  • @elmo 这是对原始问题的一个非常优雅的解决方案。我建议你把它贴在那里(见我的问题帖子中的链接)。另外,如果您将此代码+有关名称解析的评论结合到一个答案中,我会接受它。 MSalters 的回答只是指向方向,因为没有实际的构造函数解析进化(注意我的typeid 中的typename 关键字)。
  • 在这里和那里作为答案发布。如果您发现其中缺少任何内容,请告诉我。

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


【解决方案1】:

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

我会说typeid 的“编译器定义”行为太多,无法使其对上述以外的任何东西都有用。

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

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

至于TDerived04::TDerived04::TDerived04::TDerived04 是有效的,可以解释为在 TDerived04 类中,您可以使用其名称 TDerived04 来引用此类/命名空间。所以 TDerived04::TDerived04 就像从 TDerived04 指向类 TDerived04 (正如@MSalters 所说的那样,它被称为“类名注入”)。

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 好的,如果在main 中添加std::cout << ( typeid( TDerived04 ) == typeid( TDerived04::TDerived04::TDerived04::TDerived04 ) ) << std::endl;(它在GCC 下编译,但在MSVC++ 下不编译,MSVC++ 需要构造函数的参数),打印值为true。因此,MSVC++ 正试图将它视为构造函数,正如您所说的那样。但是,为什么 GCC 会打印 true?它将TDerived04 类型与......我不确定是什么,但它似乎将TDerived04::TDerived04::TDerived04::TDerived04 视为TDerived04 类型。没有?
    • 哇,GCC 允许定义 `TDerived04::TDerived04::TDerived04::TDerived04 lD4;` 变量。类型只是TDerived04。是否有折叠范围解析的规则? MSVC++ 似乎在typeid 做同样的事情,但不能处理其他场景。
    • 我想这可能是因为在 TDerived04 类中你可以使用它的名称 TDerived04 来引用这个类/命名空间。所以 TDerived04::TDerived04 就像从 TDerived04 指向类 TDerived04。这是有效的(虽然我不确定这是正确的解释)。
    • @elmo:这确实是“注入的类名”的意思。
    猜你喜欢
    • 2013-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-21
    • 1970-01-01
    • 1970-01-01
    • 2020-08-22
    • 2012-03-07
    相关资源
    最近更新 更多