Идиома C ++ для выполнения произвольного кода перед main в произвольной единице перевода

У меня есть одна единица перевода с моим main() функция и еще один ТУ без основного. Предположим даже, что я управляю только вторым и не могу коснуться первого.

Теперь, по причинам, я не буду вдаваться в подробности, я хочу иметь возможность запустить некоторый код раньше main() пробеги. Я знаю, что это можно сделать, инициализируя глобальную переменную с помощью вызова функции, но я хочу скрыть это — с минимальным использованием макросов, насколько это возможно (осмелюсь сказать, что использование макросов невозможно — возможно, это невозможно, в C ++ нет надлежащего статического блока) )

Каким будет элегантный или, скажем так, не очень уродливый способ сделать это? Чтобы быть более ясным, я ищу что-то, что обеспечило бы эту функциональность для многократного использования, а не просто что-то, чтобы заставить его работать один раз. Я хочу, чтобы это было как можно ближе к:

// ... at global scope ...
static {
// my code here
}

PS: этот вопрос связан, но не такой, как этот вопрос об инициализации статических членов класса. Это также мотивировано желанием четко опровергнуть это утверждение не может быть сделано в C ++.

Примечание: Да, я знаю о фиаско статического порядка инициализации, нет необходимости напоминать мне об этом … и я не прошу что-то, что обходит это. Очевидно, что выполнение кода статически требует некоторой осторожности.

-1

Решение

Пожалуйста, наслаждайтесь статический порядок инициализации фиаско:

int f(/* whatever args you want*/)
{
// code to be ran before main()
return 42;
}

static int _ignore = f(/*...*/);

Обратите внимание, что иногда код может не вызываться, если он не используется где-либо еще (псевдоним «оптимизирован»). Один из таких случаев — когда TU скомпилирован в статическую библиотеку (тогда неиспользуемая переменная и код могут не помещаться в исполняемый файл). (записка Е. Масковского).

4

Другие решения

Это лучшее, что я мог придумать до сих пор. Это работает, но реализация не совсем понятна.

использование

Если вы напишите:

STATIC_BLOCK {
std::cout << "Hello static block world!" << std::endl;
}

этот код будет выполняться до вашего main(), Тем не менее, обратите внимание, что запись в std::cout до main() На самом деле это не такая уж хорошая идея.

Заметки:

  • Вы должен окружите статический блочный код фигурными скобками (не нужно использовать конечную точку с запятой; спасибо @KlitosKyriacou за предложение).
  • Если вы не используете фигурные скобки, ожидайте сложно понять сообщения об ошибках.
  • Относительный порядок выполнения статического кода не гарантируется в C ++.

Реализация

В реализации статического блока используется фиктивная переменная. Чтобы гарантировать, что мы не столкнемся с какой-либо другой фиктивной переменной (например, из другого статического блока — или где-либо еще), нам нужно немного макро-машин.

#define CONCATENATE(s1, s2) s1##s2
#define EXPAND_THEN_CONCATENATE(s1, s2) CONCATENATE(s1, s2)

#define STATIC_BLOCK_IMPL2(function_name,var_name) \
static void function_name(); \
static int var_name __attribute((unused)) = (function_name(), 0) ; \
static void function_name()

#define STATIC_BLOCK_IMPL1(prefix) \
STATIC_BLOCK_IMPL2(CONCATENATE_FOR_STATIC_BLOCK(prefix,_fn),CONCATENATE_FOR_STATIC_BLOCK(prefix,_var))

#define STATIC_BLOCK STATIC_BLOCK_IMPL1(EXPAND_THEN_CONCATENATE(static_block_,__COUNTER__))

Заметки:

  • Если ваш компилятор не поддерживает __COUNTER__ (поскольку это расширение стандарта, а не его часть) — вы можете использовать __LINE__, который тоже работает. Поддержка GCC и Clang __COUNTER__,
  • __attribute__((unused)) другое расширение компилятора, хотя атрибуты поступают в язык; увидеть это обсуждение например. Если вы уроните его, вы получите предупреждение.
  • Код — C ++ 98 (без учета расширений компилятора), т. Е. Вам не нужны никакие современные поддерживаемые конструкции C ++. К сожалению, он не квалифицируется как C (где инициализаторы должны быть константами).

Первоначально вдохновленный Андреем Александреску SCOPE_EXIT трюк.

2

По вопросам рекламы [email protected]