安全且跨库边界保存的唯一类类型Id 我希望任何帮助,因为C++不是我的主要语言。
我有一个在多个库中派生的模板类。我试图找出一种方法,为每个派生类唯一地分配一个id int。我需要能够从一个静态的方法,即安全且跨库边界保存的唯一类类型Id 我希望任何帮助,因为C++不是我的主要语言。,c++,class,templates,unique,C++,Class,Templates,Unique,我有一个在多个库中派生的模板类。我试图找出一种方法,为每个派生类唯一地分配一个id int。我需要能够从一个静态的方法,即 模板 福班 { 公众: 静态int s_id() { //对于派生对象,返回id是唯一的 } // ... }; 谢谢大家! 没有标准化的东西。此外,我发现没有一种黑客是万无一失的 我能想到的最好的办法是: template < class DERIVED, int sid > class Foo { public: static
模板<派生类>
福班
{
公众:
静态int s_id()
{
//对于派生对象,返回id是唯一的
}
// ...
};
谢谢大家! 没有标准化的东西。此外,我发现没有一种黑客是万无一失的 我能想到的最好的办法是:
template < class DERIVED, int sid >
class Foo
{
public:
static int s_id()
{
return sid;
}
};
Foo<MyClass, 123456> derivedObject;
template
福班
{
公众:
静态int s_id()
{
返回sid;
}
};
Foo-derivedObject;
您可以执行以下操作:
#include <iostream>
template <int id = 5>
class blah
{
public:
static const int cid = id;
};
int main(int argc, char *argv[])
{
std::cout << blah<>::cid << " " << blah<10>::cid << std::endl;
}
#包括
模板
课堂废话
{
公众:
静态常数int-cid=id;
};
int main(int argc,char*argv[])
{
std::cout在我以前的公司中,我们通过创建一个宏来实现这一点,该宏将类名作为参数,创建一个具有唯一id的本地静态(基于类名)然后创建在返回静态成员的基类中声明的虚拟函数的重写。这样,您可以在运行时从对象层次结构的任何实例获取ID,类似于“getClass()'方法,但要简单得多。什么类型的ID?您是否在寻找原子级递增的int?如果字符串很好,那么:
static string s_id()
{
return typeid(Foo<DERIVED>).name();
}
静态字符串s_id()
{
返回typeid(Foo.name();
}
如果它需要是int,但不是自动增加,那么可以在一个128位的整数中不太可能有冲突(尽管可能比您需要的数量大)
<强>在现代C++中(03假设您使用的是最近的编译器,例如GCC)您可以使用关键字获取至少在运行时提供基本类型信息的type_info对象-这是一个标准(然后是跨平台)功能
我以wikipedia中的示例为例,添加了一个模板/继承检查,它似乎工作得很好,但我不确定int版本(这是一个利用编译器将在只读内存空间中某处具有类型名称的假设的黑客行为……这可能是一个错误的假设)
字符串标识符似乎更适合于跨平台标识,如果您可以在您的案例中使用它的话。它不兼容跨编译器,因为它给您的名称是由标准定义的“实现定义的”——正如注释中所建议的那样
完整的测试应用程序代码:
#include <iostream>
#include <typeinfo> //for 'typeid' to work
class Person
{
public:
// ... Person members ...
virtual ~Person() {}
};
class Employee : public Person
{
// ... Employee members ...
};
template< typename DERIVED >
class Test
{
public:
static int s_id()
{
// return id unique for DERIVED
// NOT SURE IT WILL BE REALLY UNIQUE FOR EACH CLASS!!
static const int id = reinterpret_cast<int>(typeid( DERIVED ).name());
return id;
}
static const char* s_name()
{
// return id unique for DERIVED
// ALWAYS VALID BUT STRING, NOT INT - BUT VALID AND CROSS-PLATFORM/CROSS-VERSION COMPATBLE
// AS FAR AS YOU KEEP THE CLASS NAME
return typeid( DERIVED ).name();
}
};
int wmain ()
{
Person person;
Employee employee;
Person *ptr = &employee;
std::cout << typeid(person).name() << std::endl; // Person (statically known at compile-time)
std::cout << typeid(employee).name() << std::endl; // Employee (statically known at compile-time)
std::cout << typeid(ptr).name() << std::endl; // Person * (statically known at compile-time)
std::cout << typeid(*ptr).name() << std::endl; // Employee (looked up dynamically at run-time
// because it is the dereference of a pointer to a polymorphic class)
Test<int> test;
std::cout << typeid(test).name() << std::endl;
std::cout << test.s_id() << std::endl;
std::cout << test.s_id() << std::endl;
std::cout << test.s_id() << std::endl;
std::cout << test.s_name() << std::endl;
Test< Person > test_person;
std::cout << test_person.s_name() << std::endl;
std::cout << test_person.s_id() << std::endl;
Test< Employee > test_employee;
std::cout << test_employee.s_name() << std::endl;
std::cout << test_employee.s_id() << std::endl;
Test< float > test_float;
std::cout << test_float.s_name() << std::endl;
std::cout << test_float.s_id() << std::endl;
std::cin.ignore();
return 0;
}
#包括
#包括//以便“typeid”工作
班主任
{
公众:
//…个人成员。。。
虚拟~Person(){}
};
类别雇员:公众人士
{
//…员工成员。。。
};
模板
课堂测试
{
公众:
静态int s_id()
{
//对于派生对象,返回id是唯一的
//不确定它对于每个类都是唯一的!!
static const int id=reinterpret_cast(typeid(派生).name());
返回id;
}
静态常量char*s_name()
{
//对于派生对象,返回id是唯一的
//始终有效,但为字符串,不是INT-但有效且跨平台/跨版本兼容
//只要你保留类名
返回typeid(派生的).name();
}
};
int wmain()
{
个人;
员工;
人员*ptr=&员工;
std::cout这是我最后做的。如果你有任何反馈(赞成,反对),请让我知道
模板<派生类>
福班
{
公众:
静态常量char*name();//将实现派生类,只需
//返回他们的类名
静态int s_id()
{
static const int id=id_factory::get_instance()->get_id(name());
返回id;
}
// ...
};
基本上,id将在进行字符串比较而不是指针比较后分配。这在速度方面并不理想,但我将id设置为静态常量,因此它只需为每个派生的id计算一次。这可以用很少的代码完成:
template < class DERIVED >
class Foo
{
public:
static int s_id()
{
return reinterpret_cast<int>(&s_id);
}
};
模板
福班
{
公众:
静态int s_id()
{
返回重新解释强制转换(&s)id;
}
};
到目前为止,我对答案不是100%满意,我已经为自己找到了一个解决方案。想法是使用typeinfo计算类型名的哈希值。加载应用程序时所有操作都只执行一次,因此没有运行时过载。此解决方案还可以使用共享库作为类型名,并且哈希值将保持一致t
这是我使用的代码。这对我来说非常有用
#include <string>
#include <typeinfo>
#include <stdint.h>
//###########################################################################
// Hash
//###########################################################################
#if __SIZEOF_POINTER__==8
inline uint64_t hash(const char *data, uint64_t len) {
uint64_t result = 14695981039346656037ul;
for (uint64_t index = 0; index < len; ++index)
{
result ^= (uint64_t)data[index];
result *= 1099511628211ul;
}
return result;
}
#else
inline uint32_t hash(const char *data, uint32_t len) {
uint32_t result = 2166136261u;
for (uint32_t index = 0; index < len; ++index)
{
result ^= (uint32_t)data[index];
result *= 16777619u;
}
return result;
}
#endif
inline size_t hash(const std::string & str) { return hash(str.c_str(), str.length()); }
//###########################################################################
// TypeId
//###########################################################################
typedef size_t TypeId;
template<typename T>
static const std::string & typeName() {
static const std::string tName( typeid(T).name() );
return tName;
}
template<typename T>
static TypeId typeId() {
static const TypeId tId = hash( typeName<T>() );
return tId;
}
#包括
#包括
#包括
//###########################################################################
//散列
//###########################################################################
#如果指针的大小=8
内联uint64_t哈希(常量字符*数据,uint64_t长度){
uint64_t结果=14695981039346656037ul;
对于(uint64_t索引=0;索引
template < class DERIVED >
class Foo
{
public:
static const char* name(); // Derived classes will implement, simply
// returning their class name
static int s_id()
{
static const int id = Id_factory::get_instance()->get_id(name());
return id;
}
// ...
};
template < class DERIVED >
class Foo
{
public:
static int s_id()
{
return reinterpret_cast<int>(&s_id);
}
};
#include <string>
#include <typeinfo>
#include <stdint.h>
//###########################################################################
// Hash
//###########################################################################
#if __SIZEOF_POINTER__==8
inline uint64_t hash(const char *data, uint64_t len) {
uint64_t result = 14695981039346656037ul;
for (uint64_t index = 0; index < len; ++index)
{
result ^= (uint64_t)data[index];
result *= 1099511628211ul;
}
return result;
}
#else
inline uint32_t hash(const char *data, uint32_t len) {
uint32_t result = 2166136261u;
for (uint32_t index = 0; index < len; ++index)
{
result ^= (uint32_t)data[index];
result *= 16777619u;
}
return result;
}
#endif
inline size_t hash(const std::string & str) { return hash(str.c_str(), str.length()); }
//###########################################################################
// TypeId
//###########################################################################
typedef size_t TypeId;
template<typename T>
static const std::string & typeName() {
static const std::string tName( typeid(T).name() );
return tName;
}
template<typename T>
static TypeId typeId() {
static const TypeId tId = hash( typeName<T>() );
return tId;
}
#include <stdint.h>
#include <stdio.h>
#define DEFINE_CLASS(class_name) \
class class_name { \
public: \
virtual uint32_t getID() { return hash(#class_name); } \
// djb2 hashing algorithm
uint32_t hash(const char *str)
{
unsigned long hash = 5381;
int c;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
DEFINE_CLASS(parentClass)
parentClass() {};
~parentClass() {};
};
DEFINE_CLASS(derivedClass : public parentClass)
derivedClass() : parentClass() {};
~derivedClass() {};
};
int main() {
parentClass parent;
derivedClass derived;
printf("parent id: %x\nderived id: %x\n", parent.getID(), derived.getID());
}
template <typename T>
struct TypeId
{
static size_t Get()
{
return reinterpret_cast<size_t>(&sDummy);
}
private:
static char sDummy;
};
template <typename T>
char TypeId<T>::sDummy; // don't care about value
#define GET_TYPE_ID static size_t GetTypeId() \
{ \
volatile const char* file = __FILE__; \
volatile uint32_t line = __LINE__; \
return (size_t)&GetTypeId; \
}
class ClassA
{
public:
GET_TYPE_ID
};
class ClassB
{
public:
GET_TYPE_ID
};