[英]How can I generate dense unique type IDs at compile time?
I'm trying to make a system of classes that are small objects, and the base class has a member that is a unique identifier that identifies the class: 我正在尝试创建一个小型对象的类系统,并且基类的成员是标识该类的唯一标识符:
class Shape
{
public:
unsigned char id;
};
template <typename T>
class Triangle : public Shape
{
T triangle_data;
};
template <typename T>
class Square : public Shape
{
T square_data;
};
template <typename T>
class ShapeBox : public Shape
{
T shapebox_data;
Shape * child_shape;
};
With the class identifier, I go through a vector of Shape * and switch on the id visible in the base class, then static cast for different behavior (to Triangle, Square, or ShapeBox and child shapes held in it respectively for the example class hierarchy) 使用类标识符,我通过Shape *的向量并切换基类中可见的id,然后针对不同的行为进行静态转换(分别为示例类层次结构中的Triangle,Square或ShapeBox和子形状) )
I could turn on RTTI, but the space cost seems fairly large, especially when the type information can be implemented as a pointer and the object size might be no bigger than a couple of bytes. 我可以打开RTTI,但是空间成本似乎相当大,特别是当类型信息可以实现为指针并且对象大小可能不大于几个字节时。 There may be millions of small objects, and I really only need static cast anyways. 可能有数百万个小物件,我真的只需要静态铸造。
Currently I can make type identifiers by using statics that are assigned values from a static monotonically incrementing counter: 目前,我可以使用从静态单调递增计数器分配值的静态来创建类型标识符:
class TypeID
{
static size_t counter;
public:
template<typename T>
static size_t value()
{
static size_t id = counter++;
return id;
}
};
size_t TypeID::counter = 1;
Ideally I want dense, unique type ID's that are available at compile time, so the compiler can perform well, like converting a switch on the type IDs into a constant time jump table, or at least a binary search tree rather than a linear time if/else chain for what might be a long list of type IDs... 理想情况下,我需要在编译时可用的密集,唯一类型ID,因此编译器可以很好地执行,例如将类型ID上的开关转换为常量时间跳转表,或者至少是二进制搜索树而不是线性时间/ else链可能是一长串的类型ID列表...
I can use boilerplate at compile time to manually assign every type ID, or I can use object/function pointers from a similar type ID class. 我可以在编译时使用样板来手动分配每个类型ID,或者我可以使用来自类似类型ID类的对象/函数指针。 Boiler plate is guaranteed to be dense (because we assign it manually) and known at compile time, but it's unmaintainable for template types. 锅炉板保证密集(因为我们手动分配)并且在编译时已知,但它对于模板类型是不可维护的。 Whenever you add a template type to a shape, you have to manually add a new type. 每当向模板添加模板类型时,都必须手动添加新类型。 The monotonic static counter is maintainable and dense, but unknown at compile time and so compile time optimizations aren't possible, and thread safety may be a concern. 单调静态计数器是可维护和密集的,但在编译时是未知的,因此编译时优化是不可能的,并且线程安全可能是一个问题。 The function pointer ID is known at compile time and maintainable, but isn't dense and won't fit into a small id type like a char. 函数指针ID在编译时是已知的并且是可维护的,但是不是密集的,并且不适合像char这样的小id类型。
Is there any way to generate type IDs that are visible to the compiler at compile time, dense, and automatically assigned, perhaps using template metaprogramming counter or some preprocessor magic in C++11 or C++14? 有没有办法生成编译时编译器可见,密集和自动分配的类型ID,可能使用模板元编程计数器或C ++ 11或C ++ 14中的一些预处理器魔术? Or is this not possible until C++ has compile time reflection? 或者这是不可能的,直到C ++有编译时反射?
Is there any way to generate type IDs that are visible to the compiler at compile time, dense, and automatically assigned, perhaps using template metaprogramming counter 有没有办法生成编译时编译器可见,密集和自动分配的类型ID,可能使用模板元编程计数器
I've developed a code which does this with few restrictions. 我已经开发了一个代码来实现这一点,但没有什么限制。 Two template specializations ID_by_T
and T_by_ID
define type <=> ID
link at compile time. 两个模板特化ID_by_T
和T_by_ID
在编译时定义type <=> ID
链接。 Type's ID is a enum constant. Type的ID是枚举常量。 If type <=> ID
link is not defined ID_by_T<type>::ID
is -1
and T_by_ID<undefinedID>::type
is null_t
predefined type. 如果未定义type <=> ID
链接ID_by_T<type>::ID
为-1
且T_by_ID<undefinedID>::type
为null_t
预定义类型。 DEF_TYPE_ID(type_name)
macro generates new ID when defines type <=> ID
link. DEF_TYPE_ID(type_name)
宏在定义type <=> ID
链接时生成新ID。 int_triangle
and char_triangle
show how to get typedef with correct type's ID and inner typedef _MyID_T
shows how to get ID of type. int_triangle
和char_triangle
显示如何获取具有正确类型ID的typedef和内部typedef _MyID_T
显示如何获取类型的ID。 The code was compiled with MS VS 2005 C++. 代码是使用MS VS 2005 C ++编译的。
The core -- type_id_map header file: 核心 - type_id_map头文件:
#ifndef __TYPE_ID_MAP__
#define __TYPE_ID_MAP__
namespace ns_type_ids {
struct null_t {};
template<class T, int ID_v>
struct ID_T_pair {
enum {ID=ID_v};
typedef T _Type;
inline static const _TCHAR * name() { return _T("unknown"); }
};
template<class T> struct ID_by_T: ID_T_pair<T, -1> {};
template<int ID_v> struct T_by_ID: ID_T_pair<null_t, ID_v> {};
template<> struct ID_by_T<null_t>: ID_T_pair<null_t, -1> {
inline static const _TCHAR * name() { return _T("null_t"); }
};
template<> struct T_by_ID<ID_by_T<null_t>::ID>: ID_by_T<null_t> {};
};
#define PREV_TYPE null_t
#define DEF_TYPE_ID(type_name) \
namespace ns_type_ids { \
template<> struct ID_by_T<type_name>: ID_T_pair<type_name, ID_by_T<PREV_TYPE>::ID+1> { \
inline static const _TCHAR * name() { return _T(#type_name); } \
}; \
template<> struct T_by_ID<ID_by_T<type_name>::ID>: ID_by_T<type_name> {}; \
};
#endif
And the use of type_id_map example in templated_cls_id.cpp : 并在templated_cls_id.cpp中使用type_id_map示例:
#include <tchar.h>
#include <iostream>
#ifdef _UNICODE
#define _tcout wcout
#else
#define _tcout cout
#endif
#include "type_id_map"
//targeted types
struct shape {};
template<class T>
struct data_t: shape {
T _data;
};
template<class T>
struct triangle: data_t<T>, ns_type_ids::ID_by_T<data_t<T> > {
typedef data_t<T> _MyID_T;
};
//begin type <=> id map
DEF_TYPE_ID(int)
#undef PREV_TYPE
#define PREV_TYPE int
DEF_TYPE_ID(double)
#undef PREV_TYPE
#define PREV_TYPE double
DEF_TYPE_ID(float)
#undef PREV_TYPE
#define PREV_TYPE float
DEF_TYPE_ID(data_t<int>)
#undef PREV_TYPE
#define PREV_TYPE data_t<int>
DEF_TYPE_ID(data_t<char>)
#undef PREV_TYPE
#define PREV_TYPE data_t<char>
//end type <=> id map
//Now targeted classes could be defined
typedef triangle<int> int_triangle;
typedef triangle<char> char_triangle;
int _tmain(int argc, _TCHAR* argv[]) {
using namespace std;
using namespace ns_type_ids;
#define out_id(type_name) \
_T("ID_by_T<") _T(#type_name) _T(">::ID: ") << ID_by_T<type_name>::ID
#define out_name(type_id) \
_T("T_by_ID<") _T(#type_id) _T(">: ") << T_by_ID<type_id>::name()
_tcout
<< out_id(null_t) << endl
<< out_id(int) << endl
<< out_id(double) << endl
<< out_id(float) << endl
<< out_id(int_triangle::_MyID_T) << endl
<< out_id(char_triangle::_MyID_T) << endl
<< out_name(-1) << endl
<< out_name(0) << endl
<< out_name(1) << endl
<< out_name(2) << endl
<< out_name(3) << endl
<< out_name(4) << endl
;
return 0;
#undef out_id
#undef out_name
}
Output: 输出:
ID_by_T<null_t>::ID: -1
ID_by_T<int>::ID: 0
ID_by_T<double>::ID: 1
ID_by_T<float>::ID: 2
ID_by_T<int_triangle::_MyID_T>::ID: 3
ID_by_T<char_triangle::_MyID_T>::ID: 4
T_by_ID<-1>: null_t
T_by_ID<0>: int
T_by_ID<1>: double
T_by_ID<2>: float
T_by_ID<3>: data_t<int>
T_by_ID<4>: data_t<char>
Requirements and restrictions: 要求和限制:
Type <=> ID
map is global and works only at compile time. Type <=> ID
映射是全局的,仅在编译时有效。 Type <=> ID
link must be defined at global namespace level using DEF_TYPE_ID
and PREV_TYPE
macro. 必须使用DEF_TYPE_ID
和PREV_TYPE
宏在全局命名空间级别定义Type <=> ID
链接。 Type <=> ID
link. 必须在定义Type <=> ID
链接之前声明“IDed”类型。 ID_by_T<self_type>
as a base class where self_type is an own type of class. 为了在类中获取自身ID,请使用ID_by_T<self_type>
作为基类,其中self_type是自己的类类型。 But why (see below)? 但为什么(见下文)? ID_by_T<base_data_type>
as a base class where base_data_type is a special base type of templated class for wich type <=> ID
link is already defined. 为了在模板化类中获取自身ID,请使用ID_by_T<base_data_type>
作为基类,其中base_data_type是用于类型的模板化类的特殊基type <=> ID
链接已经定义。 See int_triangle
and char_triangle
for example. 例如,请参见int_triangle
和char_triangle
。 Also there are other tricks to get defined ID inside a template instance. 还有其他技巧可以在模板实例中获取定义的ID。 Features 特征
type <=> ID
link definitions. ID是外部的,并在编译时自动按顺序从0开始按type <=> ID
链接定义的编译顺序分配 。 This is inevitability due to the requirement of the question. 由于问题的要求,这是不可避免的。 ISO/IEC 14882:2003 SE
. 对编译器的最低要求:仅ISO/IEC 14882:2003 SE
标准功能。 __COUNTER__
, __LINE__
, BOOST_PP_COUNTER
or based on sizeof
are not used to allocate ID: there are no side effects associated with them. 宏__COUNTER__
, __LINE__
, BOOST_PP_COUNTER
或基于sizeof
不用于分配ID:有与它们相关联无副作用。 type <=> id
map is based on external IDs known at compile time: type <=> id
映射基于编译时已知的外部ID:
ID_T_pair
template describes type <=> id
link. ID_T_pair
模板描述了type <=> id
链接。 ID_by_T
/ T_by_ID
templates are direct descendants of ID_T_pair
template. ID_by_T
/ T_by_ID
模板的直接后裔ID_T_pair
模板。 ID_by_T
template it is not necessary to define ID inside of a type (what is impossible for fundamental types). 由于ID_by_T
模板,没有必要在类型内部定义ID(基本类型不可能)。 ID_by_T<type>::ID
enum constant. 使用ID_by_T<type>::ID
枚举常量访问ID类型。 T_by_ID<ID>::_Type
inner typedef. 使用T_by_ID<ID>::_Type
内部typedef访问T_by_ID<ID>::_Type
。 name()
method of ID_T_pair
. 可选:使用ID_T_pair
name()
方法访问类型的名称。 name()
of ID_T_pair
is not used. 如果未使用ID_T_pair
方法name()
,则映射不会占用任何内存字节。 type <=> id
link can be defined in place but at global namespace level. 映射是分布式的: type <=> id
link可以在适当的位置定义,但在全局命名空间级别定义。 null_t
and ID=-1
returned in absence of type <=> ID
link. 在没有type <=> ID
链接的情况下,映射使用特殊的null类型null_t
和ID=-1
。 Today I've developed another solution to assign ID for every template instance automatically without the need to define an alias for every "IDed" template instance. 今天,我开发了另一种解决方案,可以自动为每个模板实例分配ID,而无需为每个“IDed”模板实例定义别名。 The solution named v2 is based on previous referred as v1. 名为v2的解决方案基于之前称为v1的解决方案。 The v1's feature of assigning an ID to a fundamental type is required to automatically assign unique ID to every template instance. v1为基本类型分配ID的功能是自动为每个模板实例分配唯一ID。
UPD: important note on the choosing of the only ID allocator UPD:关于选择唯一ID分配器的重要说明
The problem addressed here is related to the task but both answers. 这里解决的问题与任务有关,但两个答案都有关。 Approaches of the task implies the only ID allocator due to requirements: 由于要求,该任务的方法意味着唯一的ID分配器:
I could turn on RTTI, but the space cost seems fairly large, especially when the type information can be implemented as a pointer and the object size might be no bigger than a couple of bytes 我可以打开RTTI,但是空间成本看起来相当大,特别是当类型信息可以实现为指针并且对象大小可能不大于几个字节时
and 和
I want dense, unique type ID's that are available at compile time, so the compiler can perform well, like converting a switch on the type IDs into a constant time jump table, or at least a binary search tree 我想要在编译时可用的密集,唯一类型ID,因此编译器可以很好地执行,比如将类型ID上的开关转换为常量时间跳转表,或者至少是二进制搜索树
If more than one ID allocator is used (in a case of several libraries and developers) and TU must be interfaced on IDed types then the only way is to use GUIDs which values are rarefied and non sequential. 如果使用多个ID分配器(在多个库和开发人员的情况下)并且TU必须在IDed类型上接口,那么唯一的方法是使用GUID,其值是稀疏的和非顺序的。 But also GUID occupies 16 bytes and requires RTTI as well as type reflection. 但GUID也占用16个字节,需要RTTI和类型反射。 Otherwise in an attempt to build two libraries (which absolutely have different type <=> id
maps) interfaced on ID of types into one module either a linker generates an error (thanks to @MooingDuck for remarks) or developers will interfere with their different assignments of IDs to types obtained either manually (using v2's DEF_TYPE_ID
macro) or an ID generator (calling a complier by AUTO_TYPE_ID
macro). 否则,在尝试构建两个库(绝对具有不同type <=> id
map)的类型ID接口到一个模块中时,链接器会生成错误(感谢@MooingDuck备注)或者开发人员会干扰他们的不同分配对于手动获取的类型的ID(使用v2的DEF_TYPE_ID
宏)或ID生成器(通过AUTO_TYPE_ID
宏调用编译器)。
So there are cases which always are to be reduced to the first in order to use int ID of types: 所以有些情况总是要减少到第一个才能使用类型的int ID:
type <=> ID
map for all TU; 所有TU都有唯一的ID分配器和唯一的type <=> ID
映射type <=> ID
; type <=> ID
links, hence the first case for each TU; TU的接口不依赖于具有type <=> ID
链接的“小对象类系统”,因此每个TU的第一种情况; type <=> ID
maps, produced by different ID allocators, is to be accomplished to get the only type <=> ID
map. 由不同的ID分配器生成的type <=> ID
映射的开发人员之间的协商将被完成以获得唯一的type <=> ID
映射。 There is another approach but which does not meet "generate dense IDs" requirement. 还有另一种方法但不符合“生成密集ID”的要求。 The approach allows to get partially automatically generated a structured ID ie ID such as enum {FileID, LocalID}; typedef get_id<arg1_t>::res tmpl_arg_1_ID; ...
该方法允许部分自动生成结构化ID,即ID,例如enum {FileID, LocalID}; typedef get_id<arg1_t>::res tmpl_arg_1_ID; ...
enum {FileID, LocalID}; typedef get_id<arg1_t>::res tmpl_arg_1_ID; ...
enum {FileID, LocalID}; typedef get_id<arg1_t>::res tmpl_arg_1_ID; ...
. enum {FileID, LocalID}; typedef get_id<arg1_t>::res tmpl_arg_1_ID; ...
In this case FileID
must be assigned manually to every file where a type <=> ID
link is defined. 在这种情况下,必须手动将FileID
分配给定义了type <=> ID
链接的每个文件。 LocalID
is generated by calling a complier with __LINE__
macro. 通过使用__LINE__
宏调用编译器生成LocalID
。 LocalID
of a template is automatically assigned in a manner described below. 模板的LocalID
以下面描述的方式自动分配。 IDs of template arguments such as tmpl_arg_1_ID
is obtained automatically using get_id
template. 的模板参数例如ID tmpl_arg_1_ID
使用自动获得get_id
模板。 The main advantage of such structured IDs is that they are static and constant for every library and TU due to a constant content of included files (but versioning becomes a problem). 这种结构化ID的主要优点是它们对于每个库和TU都是静态的和常量的,因为包含文件的内容不变(但版本化成为一个问题)。 In order to apply such a structured ID a multiple nested switch statements may be used beginning with FileID, then LocalID and so on. 为了应用这样的结构化ID,可以使用从FileID开始,然后使用LocalID等多个嵌套的switch语句。
Features and differences from v1 v1的功能和不同之处
T<null_t, null_t ...>
named _BaseT where null_t
type is given for all typename arguments. 模板在模板的特殊“null”实例中采用自定义为枚举常量的唯一ID,例如名为_BaseT的T<null_t, null_t ...>
,其中为所有typename参数指定了null_t
类型。 _BaseT::ID
. 仅稀疏模板insnances的ID:它们是根据模板参数的ID计算的散列函数的值和作为_BaseT::ID
访问的模板_BaseT::ID
。 Hash function is the same as defined in xhash header in MS VS 2005. 散列函数与MS VS 2005中的xhash标头中定义的相同。 type <=> id
map uses ID=0
returned in absence of type <=> ID
link. 现在,在没有type <=> ID
链接的情况下, type <=> id
映射使用ID=0
返回。 type <=> ID
link in the map. 默认情况下,模板实例在地图中没有关联的type <=> ID
链接。 This is why get_id
template is used to access ID by type. 这就是使用get_id
模板按类型访问ID的原因。 __COUNTER__
macro is used to reduce and simplify code: PREV_TYPE
macro does not need anymore. __COUNTER__
宏用于减少和简化代码: PREV_TYPE
宏不再需要了。 data_t
from v1 due to forward declarations and internal template instance's ID. 由于前向声明和内部模板实例的ID,不需要使用来自v1的模板data_t
的技巧。 type <=> id
link with automatically generated ID is to be defined with AUTO_TYPE_ID(type_name)
macro. 现在,使用AUTO_TYPE_ID(type_name)
宏定义带有自动生成的ID的type <=> id
链接。 type <=> id
link may be defined with an ID allocated by another allocator (ie manually) using DEF_TYPE_ID(type_name, id)
macro. 此外, type <=> id
链接可以使用由另一个分配器(即手动)使用DEF_TYPE_ID(type_name, id)
宏分配的ID来定义。 But if you use both macros a resolution of collision ID assignments become a trouble. 但是如果你使用两个宏,碰撞ID分配的分辨率就会变成麻烦。 The core -- type_id_map_t_cnt header 核心 - type_id_map_t_cnt标头
#ifndef __TYPE_ID_MAP_T_CNT__
#define __TYPE_ID_MAP_T_CNT__
//use it if there is __COUNTER__ macro and rarefied random ID is allowable
namespace ns_type_ids {
typedef unsigned int uint;
typedef unsigned long long ulint;
typedef unsigned short ushort;
//`type <=> id` link
struct null_t { enum {ID=__COUNTER__}; };
template<class T, int ID_v>
struct ID_T_pair {
enum {ID=ID_v};
typedef T _Type;
inline static const _TCHAR * name() { return _T("unassigned"); }
};
//accessors for `type <=> id` link
template<class T> struct ID_by_T: ID_T_pair<T, null_t::ID> {};
template<int ID_v> struct T_by_ID: ID_T_pair<null_t, ID_v> {};
//predefined `type <=> id` link for null_t and ID=0
template<> struct ID_by_T<null_t>: ID_T_pair<null_t, null_t::ID> {
inline static const _TCHAR * name() { return _T("null_t"); }
};
template<> struct T_by_ID<ID_by_T<null_t>::ID>: ID_by_T<null_t> {};
//function for generating IDs inside an instance of class template
//2166136261U and 16777619U constants are from xhash STL implementation
template<ushort v, uint a=2166136261U>
struct hash {
enum : uint {res=(uint)((ulint)16777619U * (ulint)a ^ (ulint)v)};
};
//ternary operator ?:
template <bool, class Yes, class No>struct IIF { typedef null_t res; };
template <class Yes, class No> struct IIF<true, Yes, No> { typedef Yes res; };
template <class Yes, class No> struct IIF<false, Yes, No> { typedef No res; };
//accessor to ID of type for both `type <=> ID` link and ID of a template instance
template <class T>
struct get_id {
typedef typename IIF<
//by default there is no `type <=> ID` link for a teamplate instance
//instead ID is allocated and defined inside.
ID_by_T<T>::ID == null_t::ID
, T
, ID_by_T<T>
>::res _IDed;
// this `::ID` interface coincedences for
// ID_T_pair, a template instance T and null_t
enum : uint {res=_IDed::ID};
};
};
// DEF_TYPE_ID macro to define `type <=> id` link
#define DEF_TYPE_ID(type_name, type_id) \
namespace ns_type_ids { \
template<> struct ID_by_T<type_name>: ID_T_pair<type_name, type_id> { \
inline static const _TCHAR * name() { return _T(#type_name); } \
}; \
template<> struct T_by_ID<ID_by_T<type_name>::ID>: ID_by_T<type_name> {}; \
};
// AUTO_TYPE_ID macro to allocate new ID and define `type <=> id` link
#define AUTO_TYPE_ID(type_name) DEF_TYPE_ID(type_name, __COUNTER__)
#endif /* __TYPE_ID_MAP_T_CNT__ */
The use of type <=> id
map example in templated_cls_id.cpp 在templated_cls_id.cpp中使用type <=> id
map示例
#include <tchar.h>
#include <iostream>
#ifdef _UNICODE
#define _tcout wcout
#else
#define _tcout cout
#endif
#include "type_id_map_t_cnt"
//Now `type <=> id` link definition became very short
AUTO_TYPE_ID(int)
AUTO_TYPE_ID(double)
AUTO_TYPE_ID(float)
//Use forward declaration of a template and a specialization with null_t
//to define special base type with ID of the template
template<class T> struct tmpl_id;
template<> struct tmpl_id<ns_type_ids::null_t>;
//Now "null template" is known for the compiler
AUTO_TYPE_ID(tmpl_id<ns_type_ids::null_t>)
//The "null template" specialization
//Realy _BaseT type alias it the "null template" specialization
template<> struct tmpl_id<ns_type_ids::null_t> {
//returns the same base ID for every class instance
typedef tmpl_id<ns_type_ids::null_t> _BaseT;
//generating ID and defining its container
typedef ns_type_ids::hash<ns_type_ids::ID_by_T<_BaseT>::ID> _Hash;
//This is the ID of template tmpl_id
enum {ID=_Hash::res};
};
//Now the target template can be defined.
//tmpl_id<ns_type_ids::null_t> is the base type for all template instances.
//_BaseT is inherited from the base type.
template<class T>
struct tmpl_id: tmpl_id<ns_type_ids::null_t> {
//unique rarefied calculated ID for every class instance
typedef ns_type_ids::hash<
ns_type_ids::get_id<T>::res
, _BaseT::ID // it is already hash value
// and the second calling hash with it is not needed
> _Hash;
enum {ID=_Hash::res};
};
int _tmain(int argc, _TCHAR* argv[]) {
using namespace std;
using namespace ns_type_ids;
typedef int int_alias; //for testing behaviour on alias of int
//Now get_id is used instead of direct access with ID_by_T
#define out_id(type_name) \
_T("ID_by_T<") _T(#type_name) _T(">::ID: ") << get_id<type_name>::res
#define out_name(type_id) \
_T("T_by_ID<") _T(#type_id) _T(">: ") << T_by_ID<type_id>::name()
_tcout
<< _T("ID_by_T -- getting ID of type") << endl
<< out_id(null_t) << endl
<< out_id(int) << endl
<<_T("ID_of_T<type_alias> works as expected") << endl
<< out_id(int_alias) << endl
<< out_id(double) << endl
<< out_id(float) << endl
<< out_id(tmpl_id<null_t>) << endl
<< out_id(tmpl_id<int>) << endl
<< out_id(tmpl_id<double>) << endl
<< out_id(tmpl_id<float>) << endl
/* Next commented line generates an error to indicate
absence of ID for the char type */
//<< out_id(tmpl_id<char>) << endl
<< endl
<< _T("T_by_ID -- getting type or its name by ID") << endl
<< out_name(-1) << endl
<< out_name(0) << endl
<< out_name(1) << endl
<< out_name(2) << endl
<< out_name(3) << endl
<< out_name(4) << endl
<< out_name(5) << endl
;
return 0;
#undef out_id
#undef out_name
}
Output: 输出:
ID_by_T -- getting ID of type
ID_by_T<null_t>::ID: 0
ID_by_T<int>::ID: 1
ID_of_T<type_alias> works as expected
ID_by_T<int_alias>::ID: 1
ID_by_T<double>::ID: 2
ID_by_T<float>::ID: 3
ID_by_T<tmpl_id<null_t>>::ID: 4
ID_by_T<tmpl_id<int>>::ID: 225874304
ID_by_T<tmpl_id<double>>::ID: 225874307
ID_by_T<tmpl_id<float>>::ID: 225874306
T_by_ID -- getting type or its name by ID
T_by_ID<-1>: unassigned
T_by_ID<0>: null_t
T_by_ID<1>: int
T_by_ID<2>: double
T_by_ID<3>: float
T_by_ID<4>: tmpl_id<ns_type_ids::null_t>
T_by_ID<5>: unassigned
If you know how to calculate sequential IDs for template instances please let me know to rewrite ns_type_ids::hash
:-) 如果您知道如何计算模板实例的顺序ID,请告诉我重写ns_type_ids::hash
:-)
I think what you're asking for is basically impossible in C++. 我认为你要求的东西在C ++中基本上是不可能的。 The counter cannot be known at compile time, because individual compilation units do not know about each other, so you're pretty much on a hiding to nothing there. 计数器在编译时是不可知的,因为个别编译单元彼此不了解,所以你几乎都隐藏在那里。
Instead I'm using the following approach, which still isn't at "compile-time", but at least doesn't incur a function-call overhead when you query the type (assuming the compiler respects the inline), and is threadsafe. 相反,我正在使用以下方法,它仍然不在“编译时”,但至少在查询类型时(假设编译器遵循内联)不会产生函数调用开销,并且是线程安全的。
RuntimeID.h RuntimeID.h
//-----------------------------------------------
class CNextRuntimeID
{
protected:
static long m_NextRuntimeID;
};
//-----------------------------------------------
template<class T>
class CIntegerRuntimeTypeID: public CNextRuntimeID
{
static const long m_RuntimeID;
public:
inline static long GetRuntimeID()
{
return m_RuntimeID;
}
};
template<class T>
const long CIntegerRuntimeTypeID<T>::m_RuntimeID = CNextRuntimeID::m_NextRuntimeID++;
RuntimeID.cpp RuntimeID.cpp
long CNextRuntimeID::m_NextRuntimeID = 0;
I've thought quite a bit about this implementation, and I believe it's safe. 我对这个实现有很多想法,我相信它是安全的。 A potential issue is that m_NextRuntimeID could in theory be initialised to zero after one of the m_RuntimeIDs are, which would obviously result in duplicate values. 一个潜在的问题是m_NextRuntimeID理论上可以在其中一个m_RuntimeID之后初始化为零,这显然会导致重复值。 However, under VisualStudio at least, the initialisation to zero does not generate code, whereas the counter-based initialisations do. 但是,至少在VisualStudio下,初始化为零不会生成代码,而基于计数器的初始化则会生成代码。
Unfortunately, if you really care about code space, you may not like the fact that each of the increments are placed inside a function, and those functions take up space. 不幸的是,如果你真的关心代码空间,你可能不喜欢这样一个事实:每个增量都放在一个函数中,而这些函数占用了空间。 Less space than the usual 'static local variable' non-threadsafe approach, but space nevertheless. 比通常的“静态局部变量”非线程安全方法更少的空间,但仍然是空间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.