Day 16.
Пусть вы хотите определить какой-то
enum один разок и потом не упускать все места, где используются его значения (причём используются по-разному). В таком случае нам поможет идиома X macro!
Для начала определим базовый макрос, куда мы будем добавлять все значения:
#define COLORS \
X(Red) \
X(Green) \
X(Blue)
Теперь давайте объявим enum:
enum Color {
#define X(name) name,
COLORS
#undef X
};
Получим:
enum Color {
Red,
Green,
Blue,
};
А теперь можем использовать:
const char* ToString(Color c) {
switch (c) {
#define X(name) case name: return #name;
COLORS
#undef X
}
return "Unknown";
}
Где
switch станет:
switch (c) {
case Red: return "Red";
case Green: return "Green";
case Blue: return "Blue";
}
При необходимости добавить новое значение нужно будет только в самый первый макрос! Не будет такого, что имя значения и его строкового представления не будут одинаковы.
Иногда X macro могут вынести в отдельный
.def файл:
// colors.def
X(Red)
X(Green)
X(Blue)
// usage somewhere
enum Color {
#define X(name) name,
#include "colors.def"
#undef X
};
Вот кстати ещё один пример, когда мы можем хотеть инклудить один файл в другой несколько раз.
Делать так можно для много чего. Можно описать коды ответов:
#define ERRORS \
X(404, NotFound) \
X(500, Internal) \
X(403, Forbidden)
Или инструкции какие-нибудь:
#define INSTRUCTIONS \
X(Add, 0x01) \
X(Sub, 0x02)
Что вам там надо.
Дебагать конечно это тяжко. Как и любую макрокучу.
Почему
X? Видимо исторически. @thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.