This method works by comparing the identifiers and failing at compile time if they don't meet our requirements.
It's not entirely fool-proof since 2 arguments may be effectively the same, but not match when converted to their string identifiers. Nevertheless, it will catch most common mistakes.
Note that while this does work, am not sure I would want to commit this into production code since its relying on some quite convoluted macros and slows compilation noticeably (in my own tests with gcc at least).
Link to single file example.
Example, outputs:
Found!
Strings match? 0
Strings match? 1
Strings match? 0
Strings match? 1
C file:
#include <stdio.h>
int main(void)
{
int a = 1;
int A = 0, B = 1, C = 2, D = 3;
STATIC_ASSERT(!PP_ID_EQ(FOO, BAR));
STATIC_ASSERT(UNIQUE(A, B, C, D));
if (ELEM(a, A, B, C)) printf("Found!\n");
/* uncomment will fail to compile */
// STATIC_ASSERT(!PP_ID_EQ(MATCH, MATCH));
// STATIC_ASSERT(UNIQUE(D, A, B, C, D));
// if (ELEM(a, A, B, B)) printf("Found!\n");
printf("Strings match? %d\n", PP_ID_EQ(FOO, BAR));
printf("Strings match? %d\n", PP_ID_EQ(BAR, BAR));
printf("Strings match? %d\n", PP_STR_EQ("HELLO", "WORLD"));
printf("Strings match? %d\n", PP_STR_EQ("WORLD", "WORLD"));
}
C header:
/**
* Script to generate...
* \code{.py}
* MAX = 64
* for i in range(1, MAX):
* if i == 1:
* print('#define _PP_STRCMP_%d(a, b) ((a)[1] == (b)[1])' % (i,))
* else:
* print('#define _PP_STRCMP_%d(a, b) _PP_STRCMP_%d(a, b) && ((a)[%d] == (b)[%d])' % (i, i - 1, i, i))
* \endcode
*/
#define _PP_STRCMP_1(a, b) ((a)[1] == (b)[1])
#define _PP_STRCMP_2(a, b) _PP_STRCMP_1(a, b) && ((a)[2] == (b)[2])
#define _PP_STRCMP_3(a, b) _PP_STRCMP_2(a, b) && ((a)[3] == (b)[3])
#define _PP_STRCMP_4(a, b) _PP_STRCMP_3(a, b) && ((a)[4] == (b)[4])
#define _PP_STRCMP_5(a, b) _PP_STRCMP_4(a, b) && ((a)[5] == (b)[5])
#define _PP_STRCMP_6(a, b) _PP_STRCMP_5(a, b) && ((a)[6] == (b)[6])
#define _PP_STRCMP_7(a, b) _PP_STRCMP_6(a, b) && ((a)[7] == (b)[7])
#define _PP_STRCMP_8(a, b) _PP_STRCMP_7(a, b) && ((a)[8] == (b)[8])
#define _PP_STRCMP_9(a, b) _PP_STRCMP_8(a, b) && ((a)[9] == (b)[9])
#define _PP_STRCMP_10(a, b) _PP_STRCMP_9(a, b) && ((a)[10] == (b)[10])
#define _PP_STRCMP_11(a, b) _PP_STRCMP_10(a, b) && ((a)[11] == (b)[11])
#define _PP_STRCMP_12(a, b) _PP_STRCMP_11(a, b) && ((a)[12] == (b)[12])
#define _PP_STRCMP_13(a, b) _PP_STRCMP_12(a, b) && ((a)[13] == (b)[13])
#define _PP_STRCMP_14(a, b) _PP_STRCMP_13(a, b) && ((a)[14] == (b)[14])
#define _PP_STRCMP_15(a, b) _PP_STRCMP_14(a, b) && ((a)[15] == (b)[15])
#define _PP_STRCMP_16(a, b) _PP_STRCMP_15(a, b) && ((a)[16] == (b)[16])
#define _PP_STRCMP_17(a, b) _PP_STRCMP_16(a, b) && ((a)[17] == (b)[17])
#define _PP_STRCMP_18(a, b) _PP_STRCMP_17(a, b) && ((a)[18] == (b)[18])
#define _PP_STRCMP_19(a, b) _PP_STRCMP_18(a, b) && ((a)[19] == (b)[19])
#define _PP_STRCMP_20(a, b) _PP_STRCMP_19(a, b) && ((a)[20] == (b)[20])
#define _PP_STRCMP_21(a, b) _PP_STRCMP_20(a, b) && ((a)[21] == (b)[21])
#define _PP_STRCMP_22(a, b) _PP_STRCMP_21(a, b) && ((a)[22] == (b)[22])
#define _PP_STRCMP_23(a, b) _PP_STRCMP_22(a, b) && ((a)[23] == (b)[23])
#define _PP_STRCMP_24(a, b) _PP_STRCMP_23(a, b) && ((a)[24] == (b)[24])
#define _PP_STRCMP_25(a, b) _PP_STRCMP_24(a, b) && ((a)[25] == (b)[25])
#define _PP_STRCMP_26(a, b) _PP_STRCMP_25(a, b) && ((a)[26] == (b)[26])
#define _PP_STRCMP_27(a, b) _PP_STRCMP_26(a, b) && ((a)[27] == (b)[27])
#define _PP_STRCMP_28(a, b) _PP_STRCMP_27(a, b) && ((a)[28] == (b)[28])
#define _PP_STRCMP_29(a, b) _PP_STRCMP_28(a, b) && ((a)[29] == (b)[29])
#define _PP_STRCMP_30(a, b) _PP_STRCMP_29(a, b) && ((a)[30] == (b)[30])
#define _PP_STRCMP_31(a, b) _PP_STRCMP_30(a, b) && ((a)[31] == (b)[31])
#define _PP_STRCMP_32(a, b) _PP_STRCMP_31(a, b) && ((a)[32] == (b)[32])
#define _PP_STRCMP_33(a, b) _PP_STRCMP_32(a, b) && ((a)[33] == (b)[33])
#define _PP_STRCMP_34(a, b) _PP_STRCMP_33(a, b) && ((a)[34] == (b)[34])
#define _PP_STRCMP_35(a, b) _PP_STRCMP_34(a, b) && ((a)[35] == (b)[35])
#define _PP_STRCMP_36(a, b) _PP_STRCMP_35(a, b) && ((a)[36] == (b)[36])
#define _PP_STRCMP_37(a, b) _PP_STRCMP_36(a, b) && ((a)[37] == (b)[37])
#define _PP_STRCMP_38(a, b) _PP_STRCMP_37(a, b) && ((a)[38] == (b)[38])
#define _PP_STRCMP_39(a, b) _PP_STRCMP_38(a, b) && ((a)[39] == (b)[39])
#define _PP_STRCMP_40(a, b) _PP_STRCMP_39(a, b) && ((a)[40] == (b)[40])
#define _PP_STRCMP_41(a, b) _PP_STRCMP_40(a, b) && ((a)[41] == (b)[41])
#define _PP_STRCMP_42(a, b) _PP_STRCMP_41(a, b) && ((a)[42] == (b)[42])
#define _PP_STRCMP_43(a, b) _PP_STRCMP_42(a, b) && ((a)[43] == (b)[43])
#define _PP_STRCMP_44(a, b) _PP_STRCMP_43(a, b) && ((a)[44] == (b)[44])
#define _PP_STRCMP_45(a, b) _PP_STRCMP_44(a, b) && ((a)[45] == (b)[45])
#define _PP_STRCMP_46(a, b) _PP_STRCMP_45(a, b) && ((a)[46] == (b)[46])
#define _PP_STRCMP_47(a, b) _PP_STRCMP_46(a, b) && ((a)[47] == (b)[47])
#define _PP_STRCMP_48(a, b) _PP_STRCMP_47(a, b) && ((a)[48] == (b)[48])
#define _PP_STRCMP_49(a, b) _PP_STRCMP_48(a, b) && ((a)[49] == (b)[49])
#define _PP_STRCMP_50(a, b) _PP_STRCMP_49(a, b) && ((a)[50] == (b)[50])
#define _PP_STRCMP_51(a, b) _PP_STRCMP_50(a, b) && ((a)[51] == (b)[51])
#define _PP_STRCMP_52(a, b) _PP_STRCMP_51(a, b) && ((a)[52] == (b)[52])
#define _PP_STRCMP_53(a, b) _PP_STRCMP_52(a, b) && ((a)[53] == (b)[53])
#define _PP_STRCMP_54(a, b) _PP_STRCMP_53(a, b) && ((a)[54] == (b)[54])
#define _PP_STRCMP_55(a, b) _PP_STRCMP_54(a, b) && ((a)[55] == (b)[55])
#define _PP_STRCMP_56(a, b) _PP_STRCMP_55(a, b) && ((a)[56] == (b)[56])
#define _PP_STRCMP_57(a, b) _PP_STRCMP_56(a, b) && ((a)[57] == (b)[57])
#define _PP_STRCMP_58(a, b) _PP_STRCMP_57(a, b) && ((a)[58] == (b)[58])
#define _PP_STRCMP_59(a, b) _PP_STRCMP_58(a, b) && ((a)[59] == (b)[59])
#define _PP_STRCMP_60(a, b) _PP_STRCMP_59(a, b) && ((a)[60] == (b)[60])
#define _PP_STRCMP_61(a, b) _PP_STRCMP_60(a, b) && ((a)[61] == (b)[61])
#define _PP_STRCMP_62(a, b) _PP_STRCMP_61(a, b) && ((a)[62] == (b)[62])
#define _PP_STRCMP_63(a, b) _PP_STRCMP_62(a, b) && ((a)[63] == (b)[63])
/**
* Strings must be constant and NULL terminated.
*
* Script to generate...
* \code{.py}
* MAX = 64
* print('#define PP_STR_EQ(a, b) ( \\')
* print(' (sizeof(int[(sizeof(a) > %d ? -1 : 1)])) && \\' % MAX)
* print(' (sizeof(a) == sizeof(b)) && \\')
* print(' (((sizeof(a) == 1)) || \\')
* for i in range(2, MAX + 1):
* print(' ((sizeof(a) == %d) && _PP_STRCMP_%d(a, b)) %s' % (i, i - 1, "|| \\" if i != MAX else "))"))
* \endcode
*/
#define PP_STR_EQ(a, b) ( \
(sizeof(int[(sizeof(a) > 64 ? -1 : 1)])) && \
(sizeof(a) == sizeof(b)) && \
(((sizeof(a) == 1)) || \
((sizeof(a) == 2) && _PP_STRCMP_1(a, b)) || \
((sizeof(a) == 3) && _PP_STRCMP_2(a, b)) || \
((sizeof(a) == 4) && _PP_STRCMP_3(a, b)) || \
((sizeof(a) == 5) && _PP_STRCMP_4(a, b)) || \
((sizeof(a) == 6) && _PP_STRCMP_5(a, b)) || \
((sizeof(a) == 7) && _PP_STRCMP_6(a, b)) || \
((sizeof(a) == 8) && _PP_STRCMP_7(a, b)) || \
((sizeof(a) == 9) && _PP_STRCMP_8(a, b)) || \
((sizeof(a) == 10) && _PP_STRCMP_9(a, b)) || \
((sizeof(a) == 11) && _PP_STRCMP_10(a, b)) || \
((sizeof(a) == 12) && _PP_STRCMP_11(a, b)) || \
((sizeof(a) == 13) && _PP_STRCMP_12(a, b)) || \
((sizeof(a) == 14) && _PP_STRCMP_13(a, b)) || \
((sizeof(a) == 15) && _PP_STRCMP_14(a, b)) || \
((sizeof(a) == 16) && _PP_STRCMP_15(a, b)) || \
((sizeof(a) == 17) && _PP_STRCMP_16(a, b)) || \
((sizeof(a) == 18) && _PP_STRCMP_17(a, b)) || \
((sizeof(a) == 19) && _PP_STRCMP_18(a, b)) || \
((sizeof(a) == 20) && _PP_STRCMP_19(a, b)) || \
((sizeof(a) == 21) && _PP_STRCMP_20(a, b)) || \
((sizeof(a) == 22) && _PP_STRCMP_21(a, b)) || \
((sizeof(a) == 23) && _PP_STRCMP_22(a, b)) || \
((sizeof(a) == 24) && _PP_STRCMP_23(a, b)) || \
((sizeof(a) == 25) && _PP_STRCMP_24(a, b)) || \
((sizeof(a) == 26) && _PP_STRCMP_25(a, b)) || \
((sizeof(a) == 27) && _PP_STRCMP_26(a, b)) || \
((sizeof(a) == 28) && _PP_STRCMP_27(a, b)) || \
((sizeof(a) == 29) && _PP_STRCMP_28(a, b)) || \
((sizeof(a) == 30) && _PP_STRCMP_29(a, b)) || \
((sizeof(a) == 31) && _PP_STRCMP_30(a, b)) || \
((sizeof(a) == 32) && _PP_STRCMP_31(a, b)) || \
((sizeof(a) == 33) && _PP_STRCMP_32(a, b)) || \
((sizeof(a) == 34) && _PP_STRCMP_33(a, b)) || \
((sizeof(a) == 35) && _PP_STRCMP_34(a, b)) || \
((sizeof(a) == 36) && _PP_STRCMP_35(a, b)) || \
((sizeof(a) == 37) && _PP_STRCMP_36(a, b)) || \
((sizeof(a) == 38) && _PP_STRCMP_37(a, b)) || \
((sizeof(a) == 39) && _PP_STRCMP_38(a, b)) || \
((sizeof(a) == 40) && _PP_STRCMP_39(a, b)) || \
((sizeof(a) == 41) && _PP_STRCMP_40(a, b)) || \
((sizeof(a) == 42) && _PP_STRCMP_41(a, b)) || \
((sizeof(a) == 43) && _PP_STRCMP_42(a, b)) || \
((sizeof(a) == 44) && _PP_STRCMP_43(a, b)) || \
((sizeof(a) == 45) && _PP_STRCMP_44(a, b)) || \
((sizeof(a) == 46) && _PP_STRCMP_45(a, b)) || \
((sizeof(a) == 47) && _PP_STRCMP_46(a, b)) || \
((sizeof(a) == 48) && _PP_STRCMP_47(a, b)) || \
((sizeof(a) == 49) && _PP_STRCMP_48(a, b)) || \
((sizeof(a) == 50) && _PP_STRCMP_49(a, b)) || \
((sizeof(a) == 51) && _PP_STRCMP_50(a, b)) || \
((sizeof(a) == 52) && _PP_STRCMP_51(a, b)) || \
((sizeof(a) == 53) && _PP_STRCMP_52(a, b)) || \
((sizeof(a) == 54) && _PP_STRCMP_53(a, b)) || \
((sizeof(a) == 55) && _PP_STRCMP_54(a, b)) || \
((sizeof(a) == 56) && _PP_STRCMP_55(a, b)) || \
((sizeof(a) == 57) && _PP_STRCMP_56(a, b)) || \
((sizeof(a) == 58) && _PP_STRCMP_57(a, b)) || \
((sizeof(a) == 59) && _PP_STRCMP_58(a, b)) || \
((sizeof(a) == 60) && _PP_STRCMP_59(a, b)) || \
((sizeof(a) == 61) && _PP_STRCMP_60(a, b)) || \
((sizeof(a) == 62) && _PP_STRCMP_61(a, b)) || \
((sizeof(a) == 63) && _PP_STRCMP_62(a, b)) || \
((sizeof(a) == 64) && _PP_STRCMP_63(a, b)) ))
/* -------------------------------------------------------------------- */
#define STRINGIFY_ARG(x) "" #x
#define STRINGIFY_APPEND(a, b) "" a #b
#define STRINGIFY(x) STRINGIFY_APPEND("", x)
#define PP_ID_EQ(a, b) \
PP_STR_EQ(STRINGIFY(a), STRINGIFY(b))
#define STATIC_ASSERT(expr) \
((void)sizeof(int[(expr) ? 1 : -1]))
/* -------------------------------------------------------------------- */
/* varargs macros (keep first so others can use) */
/* --- internal helpers --- */
#define _VA_NARGS_GLUE(x, y) x y
#define _VA_NARGS_RETURN_COUNT(\
_1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, \
_17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, \
_33_, _34_, _35_, _36_, _37_, _38_, _39_, _40_, _41_, _42_, _43_, _44_, _45_, _46_, _47_, _48_, \
_49_, _50_, _51_, _52_, _53_, _54_, _55_, _56_, _57_, _58_, _59_, _60_, _61_, _62_, _63_, _64_, \
count, ...) count
#define _VA_NARGS_EXPAND(args) _VA_NARGS_RETURN_COUNT args
/* 64 args max */
#define _VA_NARGS_COUNT(...) _VA_NARGS_EXPAND((__VA_ARGS__, \
64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, \
48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, \
32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \
16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
#define _VA_NARGS_OVERLOAD_MACRO2(name, count) name##count
#define _VA_NARGS_OVERLOAD_MACRO1(name, count) _VA_NARGS_OVERLOAD_MACRO2(name, count)
#define _VA_NARGS_OVERLOAD_MACRO(name, count) _VA_NARGS_OVERLOAD_MACRO1(name, count)
/* --- expose for re-use --- */
#define VA_NARGS_CALL_OVERLOAD(name, ...) \
_VA_NARGS_GLUE(_VA_NARGS_OVERLOAD_MACRO(name, _VA_NARGS_COUNT(__VA_ARGS__)), (__VA_ARGS__))
/* -------------------------------------------------------------------- */
/* UNIQUE#(v, ...): are all args unique?
*
* Script to generate...
* \code{.py}
* for i in range(1, 16):
* args = [(chr(ord('a') + (c % 26)) + (chr(ord('0') + (c // 26)))) for c in range(i + 1)]
* print("#define _VA_UNIQUE%d(%s) \\" % (i + 1, ", ".join(args)))
* if i > 1:
* expr = ["_VA_UNIQUE%d(%s)" % (i, ", ".join(args[:-1]))]
* else:
* expr = []
* for j in range(len(args) - 1):
* expr.append("!PP_ID_EQ(%s, %s)" % (args[j], args[-1]))
* print(" (" + " && ".join(expr) + ")")
* \endcode
*/
#define _VA_UNIQUE2(a0, b0) \
(!PP_ID_EQ(a0, b0))
#define _VA_UNIQUE3(a0, b0, c0) \
(_VA_UNIQUE2(a0, b0) && !PP_ID_EQ(a0, c0) && !PP_ID_EQ(b0, c0))
#define _VA_UNIQUE4(a0, b0, c0, d0) \
(_VA_UNIQUE3(a0, b0, c0) && !PP_ID_EQ(a0, d0) && \
!PP_ID_EQ(b0, d0) && !PP_ID_EQ(c0, d0))
#define _VA_UNIQUE5(a0, b0, c0, d0, e0) \
(_VA_UNIQUE4(a0, b0, c0, d0) && !PP_ID_EQ(a0, e0) && \
!PP_ID_EQ(b0, e0) && !PP_ID_EQ(c0, e0) && !PP_ID_EQ(d0, e0))
#define _VA_UNIQUE6(a0, b0, c0, d0, e0, f0) \
(_VA_UNIQUE5(a0, b0, c0, d0, e0) && !PP_ID_EQ(a0, f0) && \
!PP_ID_EQ(b0, f0) && !PP_ID_EQ(c0, f0) && !PP_ID_EQ(d0, f0) && !PP_ID_EQ(e0, f0))
#define _VA_UNIQUE7(a0, b0, c0, d0, e0, f0, g0) \
(_VA_UNIQUE6(a0, b0, c0, d0, e0, f0) && !PP_ID_EQ(a0, g0) && \
!PP_ID_EQ(b0, g0) && !PP_ID_EQ(c0, g0) && !PP_ID_EQ(d0, g0) && !PP_ID_EQ(e0, g0) && \
!PP_ID_EQ(f0, g0))
#define _VA_UNIQUE8(a0, b0, c0, d0, e0, f0, g0, h0) \
(_VA_UNIQUE7(a0, b0, c0, d0, e0, f0, g0) && !PP_ID_EQ(a0, h0) && \
!PP_ID_EQ(b0, h0) && !PP_ID_EQ(c0, h0) && !PP_ID_EQ(d0, h0) && !PP_ID_EQ(e0, h0) && \
!PP_ID_EQ(f0, h0) && !PP_ID_EQ(g0, h0))
#define _VA_UNIQUE9(a0, b0, c0, d0, e0, f0, g0, h0, i0) \
(_VA_UNIQUE8(a0, b0, c0, d0, e0, f0, g0, h0) && !PP_ID_EQ(a0, i0) && \
!PP_ID_EQ(b0, i0) && !PP_ID_EQ(c0, i0) && !PP_ID_EQ(d0, i0) && !PP_ID_EQ(e0, i0) && \
!PP_ID_EQ(f0, i0) && !PP_ID_EQ(g0, i0) && !PP_ID_EQ(h0, i0))
#define _VA_UNIQUE10(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0) \
(_VA_UNIQUE9(a0, b0, c0, d0, e0, f0, g0, h0, i0) && !PP_ID_EQ(a0, j0) && \
!PP_ID_EQ(b0, j0) && !PP_ID_EQ(c0, j0) && !PP_ID_EQ(d0, j0) && !PP_ID_EQ(e0, j0) && \
!PP_ID_EQ(f0, j0) && !PP_ID_EQ(g0, j0) && !PP_ID_EQ(h0, j0) && !PP_ID_EQ(i0, j0))
#define _VA_UNIQUE11(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0) \
(_VA_UNIQUE10(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0) && !PP_ID_EQ(a0, k0) && \
!PP_ID_EQ(b0, k0) && !PP_ID_EQ(c0, k0) && !PP_ID_EQ(d0, k0) && !PP_ID_EQ(e0, k0) && \
!PP_ID_EQ(f0, k0) && !PP_ID_EQ(g0, k0) && !PP_ID_EQ(h0, k0) && !PP_ID_EQ(i0, k0) && \
!PP_ID_EQ(j0, k0))
#define _VA_UNIQUE12(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0) \
(_VA_UNIQUE11(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0) && !PP_ID_EQ(a0, l0) && \
!PP_ID_EQ(b0, l0) && !PP_ID_EQ(c0, l0) && !PP_ID_EQ(d0, l0) && !PP_ID_EQ(e0, l0) && \
!PP_ID_EQ(f0, l0) && !PP_ID_EQ(g0, l0) && !PP_ID_EQ(h0, l0) && !PP_ID_EQ(i0, l0) && \
!PP_ID_EQ(j0, l0) && !PP_ID_EQ(k0, l0))
#define _VA_UNIQUE13(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0) \
(_VA_UNIQUE12(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0) && !PP_ID_EQ(a0, m0) && \
!PP_ID_EQ(b0, m0) && !PP_ID_EQ(c0, m0) && !PP_ID_EQ(d0, m0) && !PP_ID_EQ(e0, m0) && \
!PP_ID_EQ(f0, m0) && !PP_ID_EQ(g0, m0) && !PP_ID_EQ(h0, m0) && !PP_ID_EQ(i0, m0) && \
!PP_ID_EQ(j0, m0) && !PP_ID_EQ(k0, m0) && !PP_ID_EQ(l0, m0))
#define _VA_UNIQUE14(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0) \
(_VA_UNIQUE13(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0) && !PP_ID_EQ(a0, n0) && \
!PP_ID_EQ(b0, n0) && !PP_ID_EQ(c0, n0) && !PP_ID_EQ(d0, n0) && !PP_ID_EQ(e0, n0) && \
!PP_ID_EQ(f0, n0) && !PP_ID_EQ(g0, n0) && !PP_ID_EQ(h0, n0) && !PP_ID_EQ(i0, n0) && \
!PP_ID_EQ(j0, n0) && !PP_ID_EQ(k0, n0) && !PP_ID_EQ(l0, n0) && !PP_ID_EQ(m0, n0))
#define _VA_UNIQUE15(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0) \
(_VA_UNIQUE14(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0) && !PP_ID_EQ(a0, o0) && \
!PP_ID_EQ(b0, o0) && !PP_ID_EQ(c0, o0) && !PP_ID_EQ(d0, o0) && !PP_ID_EQ(e0, o0) && \
!PP_ID_EQ(f0, o0) && !PP_ID_EQ(g0, o0) && !PP_ID_EQ(h0, o0) && !PP_ID_EQ(i0, o0) && \
!PP_ID_EQ(j0, o0) && !PP_ID_EQ(k0, o0) && !PP_ID_EQ(l0, o0) && !PP_ID_EQ(m0, o0) && \
!PP_ID_EQ(n0, o0))
#define _VA_UNIQUE16(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0) \
(_VA_UNIQUE15(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0) && !PP_ID_EQ(a0, p0) && \
!PP_ID_EQ(b0, p0) && !PP_ID_EQ(c0, p0) && !PP_ID_EQ(d0, p0) && !PP_ID_EQ(e0, p0) && \
!PP_ID_EQ(f0, p0) && !PP_ID_EQ(g0, p0) && !PP_ID_EQ(h0, p0) && !PP_ID_EQ(i0, p0) && \
!PP_ID_EQ(j0, p0) && !PP_ID_EQ(k0, p0) && !PP_ID_EQ(l0, p0) && !PP_ID_EQ(m0, p0) && \
!PP_ID_EQ(n0, p0) && !PP_ID_EQ(o0, p0))
/* reusable UNIQUE macro */
#define UNIQUE(...) VA_NARGS_CALL_OVERLOAD(_VA_UNIQUE, __VA_ARGS__)
/* -------------------------------------------------------------------- */
/* ELEM#(v, ...): is the first arg equal any others? */
/* internal helpers*/
#define _VA_ELEM2(v, a) \
((v) == (a))
#define _VA_ELEM3(v, a, b) \
(_VA_ELEM2(v, a) || ((v) == (b)))
#define _VA_ELEM4(v, a, b, c) \
(_VA_ELEM3(v, a, b) || ((v) == (c)))
#define _VA_ELEM5(v, a, b, c, d) \
(_VA_ELEM4(v, a, b, c) || ((v) == (d)))
#define _VA_ELEM6(v, a, b, c, d, e) \
(_VA_ELEM5(v, a, b, c, d) || ((v) == (e)))
#define _VA_ELEM7(v, a, b, c, d, e, f) \
(_VA_ELEM6(v, a, b, c, d, e) || ((v) == (f)))
#define _VA_ELEM8(v, a, b, c, d, e, f, g) \
(_VA_ELEM7(v, a, b, c, d, e, f) || ((v) == (g)))
#define _VA_ELEM9(v, a, b, c, d, e, f, g, h) \
(_VA_ELEM8(v, a, b, c, d, e, f, g) || ((v) == (h)))
#define _VA_ELEM10(v, a, b, c, d, e, f, g, h, i) \
(_VA_ELEM9(v, a, b, c, d, e, f, g, h) || ((v) == (i)))
#define _VA_ELEM11(v, a, b, c, d, e, f, g, h, i, j) \
(_VA_ELEM10(v, a, b, c, d, e, f, g, h, i) || ((v) == (j)))
#define _VA_ELEM12(v, a, b, c, d, e, f, g, h, i, j, k) \
(_VA_ELEM11(v, a, b, c, d, e, f, g, h, i, j) || ((v) == (k)))
#define _VA_ELEM13(v, a, b, c, d, e, f, g, h, i, j, k, l) \
(_VA_ELEM12(v, a, b, c, d, e, f, g, h, i, j, k) || ((v) == (l)))
#define _VA_ELEM14(v, a, b, c, d, e, f, g, h, i, j, k, l, m) \
(_VA_ELEM13(v, a, b, c, d, e, f, g, h, i, j, k, l) || ((v) == (m)))
#define _VA_ELEM15(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n) \
(_VA_ELEM14(v, a, b, c, d, e, f, g, h, i, j, k, l, m) || ((v) == (n)))
#define _VA_ELEM16(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) \
(_VA_ELEM15(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n) || ((v) == (o)))
#define _VA_ELEM17(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \
(_VA_ELEM16(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) || ((v) == (p)))
/* reusable ELEM macro */
#define ELEM(...) ((void)(sizeof(int[UNIQUE(__VA_ARGS__) ? 1 : -1])), \
VA_NARGS_CALL_OVERLOAD(_VA_ELEM, __VA_ARGS__))
Tested with gcc5.2