У меня куча статики init()
методы, которые мне нужно вызывать при запуске приложения. Вроде как надо делать:
A::init();
S::init();
//...
Один из способов сделать это — инициализировать статическую переменную следующим образом:
static bool const b{A::init(), S::init(), false};
Существуют ли более хорошие альтернативы?
Вы можете использовать экземпляр класса запуска, который инициализирует различные компоненты в своем конструкторе и завершает их в своем деструкторе. Пример:
struct Startup
{
Startup()
{
A::Init();
B::Init();
}
~Startup()
{
B::Term();
A::Term();
}
};
namespace { Startup startup; }
int main()
{
// do stuff being completely oblivious to the startup
}
Я несколько раз играл с «жизнью до начала», прежде чем понял, что это обычно более болезненно, чем необходимо.
Поэтому мой совет:
int main() {
A::init();
S::init();
// ...
}
Для ясности, возможно, стоит создать init
функция, которая будет вызывать все эти по очереди.
И если дерево зависимостей между различными библиотеками не является кристально чистым, я советую против упаковка (т.е. имея B::init
вызов A::init
) потому что в случае алмазных зависимостей вы можете получить базовую библиотеку init
вызывается несколько раз.
Не автоинициализировать. Явно инициализируйте ваши подсистемы во время запуска внутри вашего main
,
Причины:
Вы можете иметь init_dispatch
шаблон, который вызывает init()
через список переменных аргументов:
template<typename T>
struct dispatch
{
dispatch() { T::init(); }
};
template<typename... Ts>
struct init_dispatch : std::false_type
, dispatch<Ts>...
{
init_dispatch() : dispatch<Ts>{}... {}
};
static bool const b = init_dispatch<A, S>{}.value;
Лично я бы настоятельно рекомендовал сделать это простым: инициализировать вещи в пределах main
не с волшебной статикой. Таким образом, ясно, что это происходит, и это явно когда такое случается. И вы можете рассуждать о состоянии приложения до и после него.
Все, что происходит до и после main
как правило, могут привести к неприятностям в будущем.