为模板类的实例分配唯一的数字标识符

时间:2009-09-11 07:56:08

标签: c++ templates metaprogramming

核心问题: 我希望能够获取一个模板化类的实例,比如说:

template<class a, class b, class c> class foo;

foo<int, float, double>;

然后执行以下操作:

foo<int, float, double>::value;  //Evaluates to a unique number
foo<long, float, double>::value; //Evaluates to a different unique number
foo<int, float, double>::value;  //Evaulates to the same unique number

除此之外,确实如此:

template<class a, class b, class c>
int getUniqueIdentifier()
{
    return foo<a, b, c>::value;
} 

当前的解决方案尝试:
我想我想使用Boost :: MPL的“可扩展关联序列”,因为每个元素都有它自己的唯一标识符,但我想我需要能够改变序列,“插入”不做。
我可能正在咆哮错误的树。 (在正面,Dayum,但是MPL!)

目的:
重新发明信号和轮子上的轮子套接字系统。组件使用“交换机”创建和注册通道,该交换机将使用唯一标识符将通道放入映射中,从而允许运行时通用性。我已经尝试查找Qt库作为一个例子,但我无法解析他们的缩写,我想我缺少一些正式的技术诀窍。

谢谢!

8 个答案:

答案 0 :(得分:4)

如果您想将内容放入地图中,并且需要每个类型的密钥,那么正确的解决方案是使用std::type_info::before()。导出类可能是值得的,因此您可以提供operator<,或者将std::type_info::before()包装在二元谓词中。

答案 1 :(得分:2)

我碰巧在我的libs中有这个hackery(uintxx是我的typedef,有明显的意义) - 没有rtti的工作。 32/64 compat。前几个模板用于定义包含void *

的pointer_uint
namespace pgast{

template <size_t size>
struct _pointer_uint{
};

template <>
struct _pointer_uint<2>{
    typedef uint16 intrinsic;
};

template <>
struct _pointer_uint<3>{
    typedef uint32 intrinsic;
};

template <>
struct _pointer_uint<4>{
    typedef uint32 intrinsic;
};

template <>
struct _pointer_uint<5>{
    typedef uint64 intrinsic;
};

template <>
struct _pointer_uint<6>{
    typedef uint64 intrinsic;
};

template <>
struct _pointer_uint<7>{
    typedef uint64 intrinsic;
};

template <>
struct _pointer_uint<8>{
    typedef uint64 intrinsic;
};

typedef _pointer_uint< sizeof(void*) >::intrinsic pointer_uint; 

template <class c>
struct Class_Identifier{
   static pointer_uint id(){
       static char _id;
       return reinterpret_cast<pointer_uint>(&_id);
   }
   template <class c2> 
   bool operator==(const Class_Identifier<c2>& rhs)const{
      return id() == Class_Identifier<c2>::id();
   }
   template <class c2> 
   bool operator<(const Class_Identifier<c2>& rhs)const{
      return id() < Class_Identifier<c2>::id();
   }
};

}//namespace pgast

/*
Copyright (c)1993,2001 J. E. Pendergast Jr. 
*/

答案 2 :(得分:0)

碰撞的可能性很大,但为了简单起见,你无法击败:

template<class a, class b, class c>
static int getUniqueIdentifier()
{
    return sizeof( a ) + sizeof( b ) + sizeof( c );
}

答案 3 :(得分:0)

如果您在一个头文件中执行此操作,则可以使用__LINE__宏来获取一些唯一编号。但是,只要它分布在多个文件中,它们就不再是唯一的。

IIRC,VC有一些宏,其值为每次使用宏时递增的数字。所以,如果你只使用VC,你可以使用它。但是,这也仅适用于一个翻译单元。

除此之外,我不知道如何从类型中获取唯一数字。

但是,为什么不使用typeid作为地图的密钥类型?像这样:

typedef std::map< std::type_info, whatever > my_map;

template< typename a, typename b, typename c>
void register_foo(my_map& the_map, const foo<a,b,c>& some_bar, whatever the_whatever) 
{
  the_map.insert( typeid(foo<a,b,c>), the_whatever );
}

答案 4 :(得分:0)

如果启用了rtti,则可以连接类的名称,正在实例化模板,然后返回此字符串的哈希值。通过选择一个好的哈希函数,你可以减少碰撞的几率(也许你也不需要rtti,你可以自己引入一些rtti):

// basic template for gaining names of the classes:
template<typename T>
class Rtti
{
static std::string GetRTTIName() { return std::string(); }
};

// specialization for the classes, you expect to use:
template<>
class Rtti<float>
{
static std::string GetRTTIName() { return std::string("float"); }
};

答案 5 :(得分:0)

或者怎么样:

template<class a, class b, class c, int uniqueId>
class Test
{
public:
    int uid() {
        return uniqueId;
    }
};

int main(int argc, char* argv[])
{
    Test<int, int, int, 5> test1;

    std::cout << test1.uid() << std::endl;

    return 0;
}

如果您希望具有相同模板参数的所有实例具有相同的ID,则可以使用;

template<class a, class b, class c>
class TestId5 : public Test<a, b, c, 5>{};

答案 6 :(得分:0)

您是希望每个实例还是每个实例?对于后来的

template <...>
class foo 
{
public:
   static unsigned id;
};

extern unsigned fooCounter;

template <...>
unsigned foo::id = ++fooCounter;

甚至

template <...>
unsigned foo::id = reinterpret_cast<unsigned>(&id);

答案 7 :(得分:0)

重新审视这个问题;在我看来,如果我能保证模板实例化中的某些功能对于该实例化是唯一的,我可以简单地使用该函数的地址作为ID。

当我意识到我不必使用type_id中的实际字符串时,我可以使用字符串的位置。

所以,例如;

template<class a>
foo
{
    void id(){}
    ...
}

&foo<int>::id != &foo<float>::id  //?

如果这是真的,那么我可以将其用作地图的每个特殊化ID号,而不是依赖于RTTI。