#c #templates #inheritance #automation
#c #шаблоны #наследование #автоматизация
Вопрос:
Рассмотрим следующий код:
uint sNextId = 0;
uint GetNextId() { return sNextId ; }
uint GetIdCount() { return sNextId; }
class TBase<T>
{
static const uint sId = GetNextId();
...
}
class DerivedA : TBase<DerivedA>
{ ... }
class DerivedB : TBase<DerivedB>
{ ... }
... More classes ...
В какой-то момент в начале моей программы
void main()
{
... Initialization code ...
... here I can guarantee that no derived classes were created ...
... but no guarantee that all those derived classes were 'touched' here ...
AllocateMemory();
... Using allocated memory, creating derived classes ...
}
Я хочу знать, сколько производных классов имеют специализированные классы TBase<T>
, вызывая GetIdCount()
для выделения всего необходимого пространства только один раз AllocateMemory()
. У меня нет никаких динамических библиотек, но я могу связать статические библиотеки с исполняемыми файлами (которые могут использовать это TBase<T>
для создания более производных типов).
Мой вопрос к C Jedi:
Как автоматизировать процесс инициализации sId
статических элементов, чтобы sNextId
он был правильным и не увеличивался после выделения памяти? Обратите внимание, что я не хочу иметь что-то явное (т. Е. Я не хочу писать дополнительный код, кроме как для добавления нового класса C
, который наследуется TBase<C>
). В идеале механизм должен работать, просто наследовая от TBase<T>
или дополнительно наследуя от не шаблонного класса, он не должен содержать никаких таймеров или чего-либо, барьеров памяти или чего-то еще более сложного. Многопоточность не рассматривается. Классы могут дополнительно наследовать не шаблонный тип, который тоже будет работать для нас, но он не должен быть «тяжелым», а также «TBase».
Спасибо!
Комментарии:
1. статические переменные-члены не могут быть инициализированы во время объявления внутри класса.
2. Пожалуйста, расскажите нам, почему вам нужно определить ваши требования к памяти. Я не знаю, как вы можете определить свои требования к памяти, используя этот метод, не делая нереалистичных предположений, например: каждый производный класс создается один и только один раз, каждый производный класс не нуждается в дополнительной памяти и т.д.
3. @seccpur, точно, и я прошу предложить способ инициализации
sId
статических элементов перед каким-то конкретным местом в коде, спасибо.4. Вы можете определить одноэлементный унаследованный класс внутри класса.
5. @Loring, у меня есть сцена, в которой есть узлы, у каждого узла есть компоненты. Когда я создаю узел, я хочу знать, сколько существует различных типов компонентов, чтобы я мог выделить память в конструкторе для каждого типа. Каждый тип компонента наследует некоторые
TComponentBase
изsId
них. Я хочу иметь доступ к шаблонуT * Get<T>() { static_assert(is_base<T, TComponentBase>); return pComponents[T::sId]; }
Ответ №1:
Вероятно, что-то, основанное на идее, которая стоит за счетчиком nifty, — это то, что вы ищете.
Из связанной документации намерение:
Убедитесь, что нелокальный статический объект инициализируется перед его первым использованием и уничтожается только после последнего использования объекта.
Вы можете сделать это так, чтобы инициализация означала, что счетчик где-то увеличивается, следовательно, доступ к этому счетчику.
Конечно, вы все равно можете использовать CRTP для этого.
Ответ №2:
Работа с мобильного телефона, попытка короткого фрагмента.
class book
{
class empty_book: public book
{
private:
int pages = 0;
public:
static const empty_bookamp; get()
{
static const empty_book p= empty_book();
return p;
}
};
void foo()
{
int pages = empty_book::get().val();
this = empty_book::get();
}
};