#cpp
Day 35.
Как мы уже поняли, препроцессор умеет только несколько базовых операций:
• раскрывать макросы
• склеивать токены (
• работать с запятыми в списках аргументов (то бишь разделять по запятым аргументы).
Но иногда хочется делать что-то совсем человеческое. Например, написать if:
Так нельзя. Потому приходится крутиться.
Сегодня придётся напрячь думалку.
Зайдём издалека.
Давайте определим вот такой странный макрос:
Обратите внимание, что он раскрывается в 2 аргумента для другого макроса: "" и "found".
И сделаем макрос
Теперь мы можем сделать конструкцию, которая позволит нам узнать, определён ли макрос:
Теперь можем проверять:
или иначе:
Вроде схема работы понятна, но зачем это нужно, не совсем. Давайте вернёмся к изначальному примеру.
Сделаем базу:
Тогда
Теперь построим макрос
И когда используем:
Вот мы уже научились инвертировать значение.
Осталось сделать
Реализация тривиальная:
Последнее, что нам нужно, это сделать
Его мы можем собрать через знакомый нам
Конечно, в коде не обязательно писать
Жоска мне кажется. Чего только не придумают.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 35.
Как мы уже поняли, препроцессор умеет только несколько базовых операций:
• раскрывать макросы
• склеивать токены (
##)• работать с запятыми в списках аргументов (то бишь разделять по запятым аргументы).
Но иногда хочется делать что-то совсем человеческое. Например, написать if:
IF(1)(a, b)
IF(0)(a, b)
Так нельзя. Потому приходится крутиться.
Сегодня придётся напрячь думалку.
Зайдём издалека.
Давайте определим вот такой странный макрос:
#define PROBE ,found
Обратите внимание, что он раскрывается в 2 аргумента для другого макроса: "" и "found".
И сделаем макрос
CHECK:
#define TUPLE_AT_1(b,a,...) a // just return 2nd argument
#define CHECK(...) TUPLE_AT_1(__VA_ARGS__,)
Теперь мы можем сделать конструкцию, которая позволит нам узнать, определён ли макрос:
#define FOO PROBE
#define IS_FOO_IMPL(x) IS_FOO_##x
#define IS_FOO(x) CHECK(IS_FOO_IMPL(x), 0)
#define IS_FOO_FOO PROBE
Теперь можем проверять:
IS_FOO(FOO)
// CHECK(IS_FOO_IMPL(FOO), 0)
// TUPLE_AT_1(IS_FOO_IMPL(FOO), 0, )
// TUPLE_AT_1(IS_FOO_FOO, 0, )
// TUPLE_AT_1(PROBE, 0, )
// TUPLE_AT_1(, found, 0, )
// found
или иначе:
IS_FOO(BAR)
// ...
// 0
Вроде схема работы понятна, но зачем это нужно, не совсем. Давайте вернёмся к изначальному примеру.
IF(1)(A, B ) // A
IF(0)(A, B ) // B
Сделаем базу:
#define PROBE ~, 1
#define SECOND(a, b, ...) b
#define CHECK(...) SECOND(__VA_ARGS__, 0)
Тогда
CHECK(PROBE) // 1
CHECK(x) // 0
Теперь построим макрос
NOT:
#define NOT_0 PROBE
#define NOT(x) CHECK(NOT_##x)
И когда используем:
NOT(0) // CHECK(NOT_0) -> CHECK(PROBE) -> 1
NOT(1) // CHECK(NOT_1) -> NOT_1 doesn't exist -> 0
Вот мы уже научились инвертировать значение.
Осталось сделать
BOOL:
BOOL(0) = 0
BOOL(1) = 1
Реализация тривиальная:
#define BOOL(x) NOT(NOT(x))
Последнее, что нам нужно, это сделать
IF:
#define IF_0(t, f) f
#define IF_1(t, f) t
IF_0(A, B) // B
IF_1(A, B) // A
Его мы можем собрать через знакомый нам
CAT:
#define CAT(a, b) CAT_I(a, b)
#define CAT_I(a, b) a##b
#define IF(c) CAT(IF_, BOOL(c))
Конечно, в коде не обязательно писать
IF(0)/IF(1). Вместо значения может быть какой-то другой макрос, который раскроется в конкретное число. Сам макрос может прийти откуда-то снаружи. Жоска мне кажется. Чего только не придумают.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
🤯26❤5👎2🤪2
#cpp
Day 36.
Иногда используют похожую структуру для реализации
Тут фактически мы сделали конечную группу \Z_8.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 36.
Иногда используют похожую структуру для реализации
INC/DEC:
#define AT_0(a,b,c,d,e,f,g,h) a
#define AT_1(a,b,c,d,e,f,g,h) b
#define AT_2(a,b,c,d,e,f,g,h) c
#define AT_3(a,b,c,d,e,f,g,h) d
#define AT_4(a,b,c,d,e,f,g,h) e
#define AT_5(a,b,c,d,e,f,g,h) f
#define AT_6(a,b,c,d,e,f,g,h) g
#define AT_7(a,b,c,d,e,f,g,h) h
#define CAT(a,b) CAT_I(a,b)
#define CAT_I(a,b) a##b
#define INC_(n) CAT(AT_, n)(1,2,3,4,5,6,7,0)
#define DEC_(n) CAT(AT_, n)(7,0,1,2,3,4,5,6)
#define INC(n) INC_(n)
#define DEC(n) DEC_(n)
INC(6) // 7
INC(7) // 0
DEC(0) // 7
INC(DEC(INC(INC(1)))) // 3
AT_x равносильно взять элемент по индексу x, а INC/DEC просто передают сдвинутое на 1 в нужную сторону количество аргументов в нужном порядке. Тут фактически мы сделали конечную группу \Z_8.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
👍11🌚6🤯2❤1👎1🤔1