在没有类型注册或RTTI的情况下在C++中实现type_id(T)

Mic*_* Z. 11 c++ templates boost

是否可以在C++中实现type_id(T),不需要手动类型注册也不需要RTTI?

我见过的所有解决方案(包括boost :: typeindex)都基于专业化,需要手动"注册",如下所示:

class A {
public:
    BOOST_TYPE_INDEX_REGISTER_CLASS
    virtual ~A(){}
};

struct B: public A {
    BOOST_TYPE_INDEX_REGISTER_CLASS
};
Run Code Online (Sandbox Code Playgroud)

但我希望能够获得任何类型的类型ID,包括我无法在我的代码中重新定义的库类型.

Pav*_* S. 15

通常答案是"不".没有RTTI或专业化,您无法实现公平类型ID.

但有一个非常强大的技巧.这是不明显的,所以它在C++世界中并不常见.

每个现代C++编译器都支持所谓的函数pretty-print宏,它允许您获取一个函数的唯一标识符,其中包含所有类型参数的解包.

所以你可以使用类似下面的代码:

#pragma once

#undef UNIQUE_FUNCTION_ID

#if defined(_MSC_VER)
  #define UNIQUE_FUNCTION_ID __FUNCSIG__
#else     
  #if defined( __GNUG__ )
    #define UNIQUE_FUNCTION_ID __PRETTY_FUNCTION__
  #endif
#endif

template<typename T>
class TypeId
{
public:
    static int typeId()
    {
        static int s_id = HASH( UNIQUE_FUNCTION_ID );
        return s_id;
    }
};
Run Code Online (Sandbox Code Playgroud)

哪里HASH可能是你喜欢的任何好的哈希函数.

缺点:

  1. 您使用的每种类型的长字符常量都会污染您的二进制文件(但实际应用程序开销不是那么成问题,我们非常密集地使用这种方法而不会对发行版大小产生重大影响.UPD:这可以避免constexpr)
  2. 生成的类型ID不能在编译器,编译器版本甚至不同版本之间移植(通常不是问题)
  3. 并非所有编译器都支持具有语义要求的宏(MSVC,G ++和Clang就像魅力一样)
  4. 对待Tconst T&作为不同类型(但可以在散列之前通过额外处理来修复UNIQUE_FUNCTION_ID)

优点:

  1. 很容易实现
  2. 不需要RTTI并支持任意类型
  3. 适用于具有DLL/SharedObjects/DyLibs的可执行文件
  4. 程序执行之间保持稳定