Ваше решение должно быть ODR-безопасным. Стандарт C ++ требует, чтобы был только один экземпляр stati c data member auto_init_
для каждого отдельного экземпляра шаблона класса execute_at_start<>
и чтобы он инициализировался один раз.
Itanium C ++ ABI (большинство компиляторов соответствуют с ним, помимо MSV C), требуются защитные переменные для глобальных объектов (здесь auto_init_
), чтобы убедиться, что они инициализированы один раз:
Если переменная stati c области видимости функции или stati c элемент данных с неопределенной связью (т.е. член данных stati c шаблона класса ) динамически инициализируется, затем существует связанная защитная переменная, которая используется для гарантии того, что построение происходит только один раз.
Подробнее см. Itanium C ++ ABI §2.8 Переменные защиты инициализации .
Еще одно стандартное ODR-безопасное решение этой проблемы, которое не Не полагаться на охранные переменные - это счетчик Шварца . Он использовался для инициализации стандартных потоков (std::cout
и других) с самого начала C ++. В этом решении counter
- это явная защитная переменная, имеющая внешнюю связь, и она гарантирует, что только первый вызов execute_at_start
вызывает конструктор init_function
:
// Header begin.
#include <iostream>
template<void(*init_function)()>
class execute_at_start {
static inline int counter = 0;
public:
execute_at_start() {
if(!counter++)
init_function();
}
};
inline void echo() { std::cout << "echo" << std::endl; }
execute_at_start<echo> const execute_at_start_echo; // A copy in each translation unit.
// Header end.
int main() {}