Часто сталкиваюсь с необходимостью проверки неких условий внутри макроса на этапе компиляции, при том, что входные аргументы макроса могут быть заданы константами, определёнными не через #define, а через enum.
Пример - имеем некий макрос:
Код
#define m(a) (((a) == 0) ? X: ((a) == 1) ? Y: Z)
Допустиммые значения a для него только: 0, 1, 2.
Хочется сделать внутри макроса, чтобы при подстановке недопустимого значения в качестве аргумента, проект не собирался (компилятор выдавал какую-либо ошибку).
Причём в качестве аргумента могли бы выступать или константы заданные хоть #define-ом хоть enum хоть числовыми константами.
Если бы были допустимы только числовые константы, то проблем нет:
Код
#define CHECK_0 0
#define CHECK_1 1
#define CHECK_2 2
#define concatAB_(a, b) a##b
#define concatAB(a, b) concatAB_(a, b)
#define m(a) ((concatAB(CHECK_, a) == 0) ? X: (concatAB(CHECK_, a) == 1) ? Y: Z)
#define CHECK_1 1
#define CHECK_2 2
#define concatAB_(a, b) a##b
#define concatAB(a, b) concatAB_(a, b)
#define m(a) ((concatAB(CHECK_, a) == 0) ? X: (concatAB(CHECK_, a) == 1) ? Y: Z)
Для недопустимого аргумента при компиляции будет ошибка "имя CHECK_XXX не определено".
Для констант заданных #define тоже подобное решение. Но вот для выражений и констант заданных enum, этот способ не катит.
Пока приходится использовать что-то типа такой конструкции:
#define m(a) (((a) == 0) ? X: ((a) == 1) ? Y: ((a) == 2) ? Z: 1/((a) >= 0 && (a) < 3))
в расчёте на ошибку деления на ноль.
Но может быть есть более элегантное решение? Что-то в голову больше ничего не приходит......
