Если мы предположим, что include guard всегда выглядит как
#define NAME /* no more tokens here */
и , если, как вы сказали, допустима любая ошибка времени компиляции (а не только #error
), тоВы можете сделать следующее:
#define THENAMESPACE BLA
#define BLA_API_H // Comment out to get a error.
#define CAT(x,y) CAT_(x,y)
#define CAT_(x,y) x##y
#define NAMESPACE(x) static int CAT(UNUSED_,__LINE__) = CAT(CAT(THENAMESPACE,CAT(_,x)),+1);
NAMESPACE(API_H)
Здесь NAMESPACE(API_H)
пытается объединить BLA_API_H
и +
, используя ##
.
Это приводит к error: pasting "BLA_API_H" and "+" does not give a valid preprocessing token
, за исключением, если BLA_API_H
равно #define
d для «без токенов».
При наличии #define BLA_API_H
, NAMESPACE(API_H)
просто становится
static int UNUSED_/*line number here*/ = +1;
Если высоглашаясь на менее надежное решение, вы даже можете получить хорошие сообщения об ошибках:
#define THENAMESPACE BLA
#define BLA_API_H // Comment out to get a error.
#define TRUTHY_VALUE_X 1
#define CAT(x,y) CAT_(x,y)
#define CAT_(x,y) x##y
#define NAMESPACE(x) CAT(CAT(TRUTHY_VALUE_,CAT(THENAMESPACE,CAT(_,x))),X)
#if !NAMESPACE(API_H)
#error "namespace not properly defined"
#endif
Здесь, если определено BLA_API_H
, то #if !NAMESPACE(API_H)
расширяется до #if 1
.
ЕслиBLA_API_H
не определено, затем оно расширяется до #if TRUTHY_VALUE_BLA_API_HX
, а TRUTHY_VALUE_BLA_API_HX
оценивается как false
из-за неопределенности.
Проблема здесь в том, что если TRUTHY_VALUE_BLA_API_HX
случайно окажется определеннымк чему-то правдивому вы получите ложное отрицание.