为什么非多态 typeid 需要 RTTI?

Mag*_*gix 5 c++ gcc rtti c++17

我有以下一段代码:

template<typename T>
class genericHandler{public: using evt_t = T;};

template<typename T>
class specialHandler : public genericHandler<T> {  /* more stuff */ };

int main(int argc, char *argv[]) {
    
    std::any any_var = specialHandler<int>{};
    
    auto f = [&any_var](auto evtHandler) {
        using EventType = typename std::remove_reference<decltype(evtHandler)>::type ::evt_t;
        if(any_var.type() == typeid(EventType)) { std::cout << "yes" << std::endl; } else { std::cout << "no" << std::endl; }
    };

    auto h = specialHandler<int>{ };
    f(h);
}
Run Code Online (Sandbox Code Playgroud)

在 Coliru 上试试

调用时,evtHandler是非多态派生类型specialHandler。根据cppreference,我们有:

当应用于多态类型的表达式时,typeid 表达式的计算可能涉及运行时开销(虚拟表查找),否则 typeid 表达式在编译时解析。

当我用 gcc and 编译时-fno-rtti,我收到以下错误消息:

不能将“typeid”与“-fno-rtti”一起使用

RTTI 是运行时类型信息,在编译时可以推导出的非多态 typeid 的情况下应该不需要。我错过了什么 ?

Use*_*ess 4

你在问两个问题。

  1. RTTI是运行时类型信息,在非多态typeid的情况下不应该需要它...

    但这是编译器开关,而不是语言功能,因此您应该检查编译器文档

    -fno-rtti

    禁止生成有关每个具有虚函数的类的信息,以供 C++ 运行时类型识别功能(dynamic_casttypeid)使用。如果您不使用该语言的这些部分,则可以使用此标志节省一些空间。请注意,异常处理使用相同的信息,但它将根据需要生成它。该dynamic_cast运算符仍可用于不需要运行时类型信息的转换,即转换为 void * 或明确的基类。

    (我的重点)。

    因此该开关禁用整个 typeinfo 系统以节省空间。如果您愿意typeinfo(或者您想使用使用 的标准库工具typeinfo),则不要typeinfo使用编译器选项显式禁用。

  2. ...可以在编译时推导的非多态 typeid

    编辑,正如韦克利先生指出的那样,问题在于您typeid在自己的代码中明确使用了。

    虽然std::any可能能够在没有 RTTI 的情况下从顶级对象中删除存储的类型,但这取决于实现,并且如果不使用您告诉 GCC 不要生成的/ ,它绝对无法实现。std::any::type()typeidtypeinfo

哦,我忘了

  1. 我错过了什么 ?

    是的,要问你的实际问题,那就是

    我正在删除它,因为我需要解决循环模板依赖性,遗憾的是我不能在这里“简单地删除它”。我有没有不使用 RTTI 的替代方案

    当然,类型擦除不依赖于 RTTI。

    只有自动类型擦除依赖于 RTTI,并且如上所述,并非全部依赖于 RTTI。您可以避免std::any::type()或手动编写自己的可区分联合 - 您需要枚举您的类型,但只有枚举本身需要对 DU 的所有用户可见。

  • 答案确实明确回答了为什么“typeid”不起作用。这是因为 GCC 标志禁用了整个“typeinfo”系统。我真的不确定我能说得清楚多少。如果您不喜欢 GCC 文档本身,请与他们一起讨论。 (2认同)