Как принудительно инициализировать статический элемент в типах шаблонов? или как получить количество всех классов, которые были получены из типа шаблона?

#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();
           }
      };