【问题标题】:Weird undefined reference error using typeid() in a CRTP [duplicate]在 CRTP 中使用 typeid() 出现奇怪的未定义引用错误 [重复]
【发布时间】:2016-08-26 05:33:36
【问题描述】:

关于为this question 提供解决方案,我尝试简化答案中提供的代码以使用RTTI 和typeid() 函数来检索类名:

#include <iostream>
#include <string>
#include <typeinfo>

struct IDriver {
    // Public virtual API:
    virtual void func1() = 0;
    // ...
    virtual ~IDriver() {}
};

class SpecificDriver;

template<typename Derived>
class Driver : public IDriver {
public:
    Driver() {
         std::cout << typeid(*this).name() << std::endl;
         std::cout << typeid(Derived).name() << std::endl;
    }  
    virtual ~Driver() {}
};

class SpecificDriver : public Driver<SpecificDriver> {
public:
    // Public virtual API:
    virtual void func1();
    virtual ~SpecificDriver() {}
};

int main() {
    SpecificDriver sd;
}

Using this code 导致链接器错误:

/tmp/ccXnTrfe.o: In function `main':
main.cpp:(.text.startup+0x4f): undefined reference to `typeinfo for SpecificDriver'

为什么这会导致 typeinfo 的未定义引用错误,而不是缺少 func1() 定义(顺便说一句,它甚至没有使用)?


有趣的是,当我删除所有 virtual 的东西时,它工作得很好:

#include <iostream>
#include <string>
#include <typeinfo>

template<typename Derived>
class Driver {
public:
    Driver() {
         std::cout << typeid(*this).name() << std::endl;
         std::cout << typeid(Derived).name() << std::endl;
    }  
};

class SpecificDriver : public Driver<SpecificDriver> {
};

int main() {
    SpecificDriver sd;
}

输出:

6DriverI14SpecificDriverE
14SpecificDriver

Demo

那么这真的和vtable generation有关吗?

【问题讨论】:

  • 您为什么使用virtual 会员? CRTP 用于静态多态性。
  • @TemplateRex 我很清楚。这是因为引入了公共 API。这是否与我的错误有关?
  • @TemplateRex 有趣的是,它是seems to matter
  • 如果这是由其他人发布的,OP 将作为“未定义引用”线程的副本关闭
  • @M.M 请把我带到涉及这种特殊情况的相应部分。

标签: c++ undefined-reference crtp typeinfo


【解决方案1】:

那么为什么在SpecificDriver 中错过了virtual void func1(); 的实现

// Public virtual API:
virtual void func1();

导致关于错过typeinfo的消息?

详细答案可以在这里找到:

http://www.hexblog.com/wp-content/uploads/2012/06/Recon-2012-Skochinsky-Compiler-Internals.pdf

或这里http://www.avabodh.com/cxxin/virtualfunction.html

简短的回答,因为对于 gccclang 编译器实现 rtti 通过vtable 查找classvtable

如果你编译代码没有优化,gcc会给你:

对 `vtable for SpecificDriver' 的未定义引用

对 `typeinfo for SpecificDriver' 的未定义引用

coliru默认使用-O2优化级别,所以优化代码如下:

auto p1 = get_ptr_to_vtable();
auto p2 = get_ptr_to_typeinfo(p1);

只是

auto p2 = CONSTANT;

并且只给出关于丢失类型信息的错误。

【讨论】:

  • 但是为什么链接器会抱怨typeinfo?此外,func1() 甚至没有在任何地方被调用。
  • typeid 使用的 vtable 和信息是在您定义第一个声明的虚函数的地方定义的。如果你不定义它,你也没有定义这些。
  • 确实是您的答案fixes that,但我仍然对链接器错误消息感到困惑。
  • 可能它以与 vtable 相同的单位生成 rtti,并且由于缺少主体而从未生成 vtable
  • 可能是因为您使用的是 gcc,其 documentation 声明类型信息与类的 vtable 一起写出(在您的情况下缺少)
【解决方案2】:

基本上这个问题是g++ undefined reference to typeinfo的重复。

注意,根据标准,程序是病态的,不需要诊断,如果没有定义所有的非纯虚函数:

N4582 [basic.def.odr]p3

如果不是纯的,则虚拟成员函数是 odr-used。

N4582 [basic.def.odr]p4

每个程序都应包含该程序中 odr 使用的每个非内联函数或变量的准确定义;无需诊断。 [...] 内联函数应在使用 odr 的每个翻译单元中定义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-03
    • 1970-01-01
    • 2012-05-16
    • 2018-03-05
    • 2014-11-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多