在编译时生成唯一类型标识符

时间:2014-01-01 13:15:55

标签: c++

我需要一种方法来为任何类型生成唯一标识符(字符串或整数),以便在一组模板函数中使用。 type_info::name()的文档说对于不同类型可能会有所不同,也可能没有什么不同,这让我很担心,因为我需要依赖它们是唯一的。 hash_code可能也不是唯一的(从名称来看,我没有看过标准对此有何看法)。

我的问题主要是,在typeid(T).name() 的情况下,

由于类型可以来自不同的(DLL)模块,因此我不能简单地使用全局计数器和模板静态函数。但是线程安全不是问题,因为可能需要类型ID的函数一次只能被一个线程调用。

2 个答案:

答案 0 :(得分:3)

  

我需要一种方法来生成唯一标识符(字符串或   对于在一组模板函数中使用的任何类型的整数)。

这些内容会有所帮助吗?

#include <cstdint>
#include <iostream>
using namespace std;

template <typename T>
class unique_id {
  static char type_id;
public:
  static uintptr_t get_ID() { return reinterpret_cast<uintptr_t>(&type_id); }
};

template <typename T>
char unique_id<T>::type_id;

struct { } s;

int main() {
  cout << unique_id<int          >::get_ID() << endl;
  cout << unique_id<double       >::get_ID() << endl;
  cout << unique_id<decltype(s)  >::get_ID() << endl;
  cout << unique_id<size_t       >::get_ID() << endl;
  cout << unique_id<unsigned long>::get_ID() << endl; 
}

LLVM代码库中有类似的,因为它不使用RTTI。但是,我没有找到该技巧的描述。即使是30分钟的谷歌搜索也无济于事;我放弃了。

  

我的问题主要是,在什么情况下,typeid(T).name()不是唯一的?

我不知道答案。我的猜测是标准并没有强制要求;当然,它没有回答问题的原因。

好的,请参阅Michael J's answer


更新:至于std::type_info::name(),标准似乎没有保证;返回的字符串对于多种类型可以是相同的,并且在同一程序的调用之间进行更改。

一个选择是深入实现定义的土地:我只是在我关心的类型以及我关心的所有平台和编译器上测试它。如果它工作正常,那么我可能会冒险。

但是,std::type_info::operator==std::type_info::operator!=可以解决您的问题:您可以区分彼此的类型,甚至可以保证它们。在您的应用程序中是否比较字符串或type_info对象是否重要?

答案 1 :(得分:0)

有时,多个名称可以引用相同的类型。希望下面的例子能给你一个想法

#include <typeinfo>
#include <iostream>

int main()
{
    class Foo
    {
    };
    class Bar : public Foo
    {
    };
    typedef int my_int;
    std::cout << "int8_t        = " << typeid(int8_t).name() << std::endl;
    std::cout << "int16_t       = " << typeid(int16_t).name() << std::endl;
    std::cout << "int32_t       = " << typeid(int32_t).name() << std::endl;
    std::cout << "int64_t       = " << typeid(int64_t).name() << std::endl;
    std::cout << "short         = " << typeid(short).name() << std::endl;
    std::cout << "short int     = " << typeid(short int).name() << std::endl;
    std::cout << "int           = " << typeid(int).name() << std::endl;
    std::cout << "long          = " << typeid(long).name() << std::endl;
    std::cout << "long int      = " << typeid(long int).name() << std::endl;
    std::cout << "long long     = " << typeid(long long).name() << std::endl;
    std::cout << "long long int = " << typeid(long long int).name() << std::endl;
    std::cout << "my_int        = " << typeid(my_int).name() << std::endl;
    std::cout << "Foo           = " << typeid(Foo).name() << std::endl;
    std::cout << "Bar           = " << typeid(Bar).name() << std::endl;

    return 0;
}

int8_t        = signed char
int16_t       = short
int32_t       = int
int64_t       = __int64
short         = short
short int     = short
int           = int
long          = long
long int      = long
long long     = __int64
long long int = __int64
my_int        = int
Foo           = ?AVFoo@?1?main@
Bar           = ?AVBar@?1?main@