13

我在互联网上的某个地方找到了一个简单的解决方案,用于没有内置 C++ RTTI的身份类。

template <typename T>
class Identity {
public:
    static int64_t id()
    {
        static int64_t dummy;
        return reinterpret_cast<int64_t>(&dummy);
    }
};

当我们需要一些类 ID 时,我们只需使用:

Identity<OurClass>::id();

我想知道,有没有碰撞?它可以为不同的类返回相同的 ID,还是为相同的类返回不同的 ID?我已经用具有不同优化值的 g++ 尝试了这段代码,一切似乎都很好。

4

3 回答 3

12

首先:有一个专门用于包含指针的整数类型:

  • intptr_t
  • 在 C++11 中uintptr_t

其次,即使实际上在 gcc 上它们是相等的,指向对象的指针的大小和函数指针(或指向成员的指针)的大小也可能不同。因此,最好使用特定对象而不是方法本身(为了符合标准)。

第三,它只给你身份,而 RTTI 更丰富,因为它知道给定对象可以转换为的所有子类,甚至允许跨虚拟继承进行交叉转换或转换。

尽管如此,我猜更正后的版本还是有用的:

struct Foo {
    static intptr_t Id() {
        static boost::none_t const Dummy = {};
        return reinterpret_cast<intptr_t>(&Dummy);
    }
};

在层次结构中,有一个virtual返回该 ID 的函数。

为了完整起见,我将提到 Clang 和 LLVM 在没有 RTTI 的情况下有自己的处理对象识别的方式。您可能想了解他们的实施方式isacast以及dyn_cast 在这里

于 2012-06-17T11:23:26.377 回答
0

此解决方案将函数指针强制转换为int. int尽管在实践中,不能保证这个指针适合sizeof(void *) == sizeof(void (*)()) <= sizeof(int)

编辑:我的坏。在 x86_64 sizeof(int) = 4, sizeof(void (*)()) = 8, 所以冲突是可能的并且是不可预测的。

您可以转换为适当大小的积分,但理论上它仍然是未定义的行为。

于 2012-06-17T11:11:25.860 回答
0

这个版本避免了未定义的行为(和编译器警告):

template <typename T>
class Identity {
public:
    static const int* id() { static const int id = 0; return &id; }
};
于 2012-06-17T11:23:27.393 回答