Макросы, которые вызывают макросы
интро
Отнсительно недавно, примерно с год назад, изучая libuv, наткнулся на отличный прием работы с препроцессором. Уже позже выяснилось что называется он X-macro и позволяет в макросах вызывать другие макросы. С его помошью очень легко избежать дублирования и ошибок в задачах где перечисления надо конвертировать в строки, давать строковые имена битовым флагам, рефлексии, сериализации и т.п.
пример
Перечисление с кодами ошибок и строкой с описанием:
#define JSON_ERRNO_MAP(XX) \
XX(OK, "ok") \
XX(BAD_NUMBER, "bad number") \
XX(BAD_STRING, "bad string") \
XX(BAD_IDENTIFIER, "bad identifier") \
XX(STACK_OVERFLOW, "stack overflow") \
XX(STACK_UNDERFLOW, "stack underflow") \
XX(MISMATCH_BRACKET, "mismatch bracket") \
XX(UNEXPECTED_CHARACTER, "unexpected character") \
XX(UNQUOTED_KEY, "unquoted key") \
XX(BREAKING_BAD, "breaking bad") \
XX(ALLOCATION_FAILURE, "allocation failure")
enum JsonErrno {
#define XX(no, str) JSON_##no,
JSON_ERRNO_MAP(XX)
#undef XX
};
const char *jsonStrError(int err) {
switch (err) {
#define XX(no, str) \
case JSON_##no: \
return str;
JSON_ERRNO_MAP(XX)
#undef XX
default:
return "unknown";
}
}
После препроцессора первращается в:
enum JsonErrno {
JSON_OK,
JSON_BAD_NUMBER,
JSON_BAD_STRING,
JSON_BAD_IDENTIFIER,
JSON_STACK_OVERFLOW,
JSON_STACK_UNDERFLOW,
JSON_MISMATCH_BRACKET,
JSON_UNEXPECTED_CHARACTER,
JSON_UNQUOTED_KEY,
JSON_BREAKING_BAD,
JSON_ALLOCATION_FAILURE,
};
const char *jsonStrError(int err) {
switch (err) {
case JSON_OK:
return "ok";
case JSON_BAD_NUMBER:
return "bad number";
case JSON_BAD_STRING:
return "bad string";
case JSON_BAD_IDENTIFIER:
return "bad identifier";
case JSON_STACK_OVERFLOW:
return "stack overflow";
case JSON_STACK_UNDERFLOW:
return "stack underflow";
case JSON_MISMATCH_BRACKET:
return "mismatch bracket";
case JSON_UNEXPECTED_CHARACTER:
return "unexpected character";
case JSON_UNQUOTED_KEY:
return "unquoted key";
case JSON_BREAKING_BAD:
return "breaking bad";
case JSON_ALLOCATION_FAILURE:
return "allocation failure";
default:
return "unknown";
}
}