Я не думаю, что есть какой-либо способ для генерации индексов во время компиляции, кроме как с использованием enum
(что я бы посчитал вполне разумным подходом).Я не уверен, что шаблон помог бы, потому что шаблоны являются чисто функциональными, и негде хранить какое-либо глобальное состояние (то есть текущий индекс), кроме имени самого шаблонного типа (что именно вы пытаетесьчтобы избежать).
Если вам действительно нужны целочисленные идентификаторы, вероятно, их проще всего настроить во время выполнения, чем пытаться слишком усердно.
Во-первых, создайте объект, представляющий тип, и используйтетипичный подход hand-made-RTTI: каждый класс должен иметь статический экземпляр этого объекта, а его виртуальная функция get-type-info возвращает указатель на этот объект.Таким образом, в каждом классе будет немного кода, например:
static TypeInfo ms_type_info;
virtual const TypeInfo *GetTypeInfo() const {
return &ms_type_info;
}
И вы определяете информацию о типе, помещая в раздел <<whatever you info you want>>
любую информацию, которую TypeInfo
сохраняет всделайте его лучше, чем RTTI компилятора;
TypeInfo WhateverClass::ms_type_info(<<whatever info you want>>);
(Каждая реализация, которую я видел, использует макрос для автоматизации создания этих двух битов текста; немного уродливо, но ваши возможности ограничены,и это лучше, чем печатать его.)
Сама структура TypeInfo
будет выглядеть примерно так:
struct TypeInfo {
int type_index;
TypeInfo *next;
TypeInfo(<<whatever>>) {<<see below>>}
};
Если бы читатель предпочел функции get и set, он мог бы иметьте.
Объект TypeInfo
должен быть статическим по отношению к классу, а не к функции, поскольку целью является создание списка всех TypeInfos
.У вас есть два варианта здесь.В автоматическом режиме каждый TypeInfo
в конструкторе, который оставлен пустым, добавляется в какой-то глобальный связанный список;другая - иметь большую функцию, которая добавляет нужные в глобальный список вручную.
Затем при запуске пробежите объекты TypeInfo
и присвойте каждому индекс.Примерно так и поступило бы, предполагая, что есть TypeInfo *g_first_type_info
, который указывает на первую информацию о типе в списке:
int next_type_index=0;
for(TypeInfo *ti=g_first_type_info;ti;ti=ti->next)
ti->type_index=next_type_index++;
Теперь, когда вам нужен ваш целочисленный идентификатор, вы можете легко получить его:
object->GetTypeInfo()->type_index;
Вы можете легко реализовать t
сейчас:
virtual int t() const {
return ms_type_info.type_index;
}
Полное раскрытие проблем, о которых я могу думать:
Типиндексы не устанавливаются во время компиляции, поэтому, если вы собираете массивы, вам нужно создавать их во время выполнения.Это может быть пустой тратой кода, если ваши массивы иначе были бы постоянными времени компиляции - однако для компиляторов, которые не поддерживают синтаксис инициализации массива в стиле C99, это может иногда сделать код более читабельным.
Если вам нравится делать все в глобальных конструкторах до запуска main
, вы можете открепиться, поскольку объекты TypeInfo
являются просто обычными глобальными объектами и (в любом случае, в этой ситуации) все равно не готовы для использованияпока не будут назначены индексы типов.
Линкеры имеют тенденцию отбрасывать глобальные объекты, которые, кажется, не используются, поэтому объекты информации типа в статических библиотеках могут никогда не добавить себя всписок.Таким образом, вы должны иметь в виду, что хотя автоматический подход к регистрации работает хорошо, когда он не работает, он не работает, так что в конечном итоге вам, в любом случае, придется регистрировать вещи вручную.