#c #define-syntax
#c #определить-синтаксис
Вопрос:
Я пытаюсь создать логическую систему, использующую макросы defines для реализации моего регистратора, которая превратится в ничто, когда будут определены определенные переключатели. Проблема в том, что когда я складываю несколько таких переключателей, вложенных один в другой (например, при вызове макроса, подобного функции IF_SWITCH_1), я получаю множество ошибок, перечисленных в блоке кода. Что вызывает эти ошибки? Как я мог их исправить?
//Creation of the switches
#define _ADD_PARTS2(part1, part2, ...) part1 ## part2 (__VA_ARGS__)
#define _ADD_PARTS(part1, part2, ...) _ADD_PARTS2(part1, part2, __VA_ARGS__)
#define _LOGIC_SWITCH_(name, cond, ...) _ADD_PARTS(name, cond, __VA_ARGS__)
//Toggles
#define CONDITION_1 true
#define CONDITION_2 true
//Switches
#define IF_SWITCH_2_true(a, b, c) std::cout << "Passed" << std::endl
#define IF_SWITCH_2_false(...)
#define IF_SWITCH_2(a, b, c) _LOGIC_SWITCH_(IF_SWITCH_2_, CONDITION_1, a, b, c)
#define IF_SWITCH_1_true(a, b, c) IF_SWITCH_2(a, b, c)
#define IF_SWITCH_1_false(...)
#define IF_SWITCH_1(a, b, c) _LOGIC_SWITCH_(IF_SWITCH_1_, CONDITION_1, a, b, c)
//Use
IF_SWITCH_2(1, 1, 1); //Compiles and passes
IF_SWITCH_1(1, 1, 1); //"IF_SWITCH_2" was not declared in this scope;
//_LOGIC_SWITCH_ was not declared in this scope;
//Use of undeclared indentifier IF_SWITCH_2_
//Switching on and off
#undef CONDITION_2
#define CONDITION_2 false //Any invocation from this point on wont pass past the logic switch
IF_SWITCH_2(1, 1, 1); //Wont pass
Насколько я знаю, изменение порядка определений не повлияло на ошибки.
Скомпилирован с 64-разрядной версией MinGW 8.10
Комментарии:
1. Так почему бы просто не
#if CONDITION_2 ..... #else .... #endif
?2. Я хочу иметь возможность переключать эти переключатели для частей кода ie.
#undef CONDITION_1
и#define CONDITION_1 false
который с этого момента отключит все переключатели в реализации макроса.#if
не может быть реализован подобным образом.3. Так почему бы просто не
#define IF_SWITCH_1(a, b, c) (CONDITION_1 ? std::cout << "Passed" << std::endl : (void)0)
? Тем не менее, расширение макроса в ничто очень сбивает с толку циклами иif
s, т.Е.while (true) IF_SWITCH_1(1, 1, 1)
— когдаIF_SWITCH_1
он расширяется в ничто, он переходит к следующему оператору…4. Проблема в том, что логика, связанная с протоколированием, намного сложнее, чем показано здесь в сокращенном виде (серьезность журнала, флаги для того, что регистрировать и т.д.). Я боюсь, что это в сочетании с частотой использования действительно увеличит время компиляции (особенно при компиляции в режиме отладки). Из-за этого я бы предпочел, чтобы макросы действительно могли расширяться в ничто, даже если
(true == true)
инструкции могли бы работать так же хорошо, как и не должны (как насчет режима отладки?) оказывает какое-либо влияние на производительность5. Это не решает вопрос, но имена, которые начинаются с символа подчеркивания, за которым следует заглавная буква (
_ADD_PARTS2
и т.д.), И имена, которые содержат два последовательных подчеркивания, зарезервированы для использования реализацией. Не используйте их в своем коде.
Ответ №1:
Что вызывает эти ошибки?
Расширения выполняются примерно один раз. Как только макрос развернут, он не будет развернут снова, также при вызовах вложенного макроса. В любом случае цепочка:
IF_SWITCH_1(1, 1, 1)
_LOGIC_SWITCH_(IF_SWITCH_1_, CONDITION_1, 1, 1, 1) // step 2
_ADD_PARTS(IF_SWITCH_1_, true, 1, 1, 1)
_ADD_PARTS2(IF_SWITCH_1_, true, 1, 1, 1)
IF_SWITCH_1_true(1, 1, 1)
IF_SWITCH_2(1, 1, 1)
_LOGIC_SWITCH_(IF_SWITCH_2_, CONDITION_1, 1, 1, 1)
// _LOGIC_SWITCH_ was expanded at step #2
_LOGIC_SWITCH_(IF_SWITCH_2_, true, 1, 1, 1)
// expanding stops here
Как я мог их исправить?
Прежде всего, идентификаторы с начальным подчеркиванием, за которым следует заглавная буква, зарезервированы для реализации. Не используйте такие идентификаторы в своем собственном коде.
Если вы хотите выполнить оценку во время выполнения, я предлагаю для:
static inline void if_switch_2_execute(int a, int b, int c) {
std::cout << "passed" << std::endl;
}
#define IF_SWITCH_2(a, b, c) (CONDITION_2?if_switch_2_execute(a, b, c):(void)0)
#define IF_SWITCH_1(a, b, c) (CONDITION_1?IF_SWITCH_2(a, b, c):(void)0)
В любом случае, исправление заключается в перемещении вычисления _LOGIC_SWITCH_
из вложенного вызова внутри _LOGIC_SWITCH_
на верхний уровень, так что _LOGIC_SWITCH_
оно расширяется только один раз в пределах одной цепочки вычислений (я не знаю, как это объяснить, вот как я это понимаю … : / ). Вот почему это обычно делается #define MACRO(something) CHOOSE_FUNCTION_TO_CALL(__VA_ARGS__)(__VA_ARGS__)
.
#define CONDITION_1 true
#define CONDITION_2 true
#define CONCAT(a, b) a##b
#define XCONCAT(a, b) CONCAT(a, b) // this is your _LOGIC_SWITCH_
#define IF_SWITCH_2_true(a, b, c) std::cout << "Passed" << std::endl
#define IF_SWITCH_2_false(...)
#define IF_SWITCH_2(a, b, c) XCONCAT(IF_SWITCH_2_, CONDITION_2)(a, b, c)
#define IF_SWITCH_1_true(a, b, c) IF_SWITCH_2(a, b, c)
#define IF_SWITCH_1_false(...)
#define IF_SWITCH_1(a, b, c) XCONCAT(IF_SWITCH_1_, CONDITION_1)(a, b, c)
Комментарии:
1. Спасибо за ответ. Все еще хотел бы знать, почему это так, но я думаю, это укажет мне правильную продолжительность.
2.
why that is
, ну, почему что?_LOGIC_SWITCH_
расширяется вIF_SWITCH_1
. Таким образом, второй раз_LOGIC_SWITCH_
изIF_SWITCH_2
не будет расширен, потому что он уже был расширен один раз. Каждый макрос расширяется только один раз в одной цепочке. Это знаменитый технический термин для макрорасширений «помеченный синим». В любом случае, 6.10.3.4p2:Furthermore, if any nested replacements encounter the name of the macro being replaced, it is not replaced
3. Это отвечает на это. Спасибо