在CRTP中使用typeid()的奇怪的未定义引用错误

时间:2016-05-01 10:45:18

标签: c++ undefined-reference crtp typeinfo

关于为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()定义(它甚至没有使用BTW)?

有趣的是,当我删除所有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有关?

2 个答案:

答案 0 :(得分:2)

那么为什么错过了virtual void func1();

SpecificDriver的实施
// 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通过class vtable vtable查找coliru

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

  

未定义引用'vtable for SpecificDriver'

     

未定义引用'typeinfo for SpecificDriver'

-O2默认情况下使用auto p1 = get_ptr_to_vtable(); auto p2 = get_ptr_to_typeinfo(p1); 优化级别,因此它会像这样优化代码:

auto p2 = CONSTANT;

{{1}}

并仅提供有关错过的typeinfo的错误。

答案 1 :(得分:1)

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

请注意,根据标准,如果没有定义所有非纯虚函数,则程序格式错误,无需诊断:

N4582 [basic.def.odr] p3

  

虚拟成员函数如果不纯,则使用odr。

N4582 [basic.def.odr] p4

  

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