// Get Nth argument. #define CPP_NTH(_0, _1, _2, _3, n, ...) n // Get number of arguments (uses gcc/clang extension for empty argument). #define CPP_ARGC(...) CPP_NTH(_0, ##__VA_ARGS__, 3, 2, 1, 0) // Utility to concatenate preprocessor tokens. #define CONCAT2(lhs, rhs) lhs##rhs #define CONCAT1(lhs, rhs) CONCAT2(lhs, rhs) #define ARGS0() #define ARGS1() a0 #define ARGS2() a1, ARGS1() #define ARGS3() a2, ARGS2() // Invoke correct ARGSn macro depending on #arguments. #define ARGS(...) CONCAT1(ARGS, CPP_ARGC(__VA_ARGS__))() #define TYPEDARGS0() #define TYPEDARGS1(ty) ty a0 #define TYPEDARGS2(ty, ...) ty a1, TYPEDARGS1(__VA_ARGS__) #define TYPEDARGS3(ty, ...) ty a2, TYPEDARGS2(__VA_ARGS__) // Invoke correct TYPEDARGSn macro depending on #arguments. #define TYPEDARGS(...) CONCAT1(TYPEDARGS, CPP_ARGC(__VA_ARGS__))(__VA_ARGS__) #define MOCK_WRAPPER_IMPL(ret, fn) \ /* do common work */ \ static ret wrap_##fn(...); // Utility to generate wrapper boilerplate. #define WRAP(ret, fn, ...) \ MOCK_WRAPPER_IMPL(ret, fn) \ \ extern "C" ret fn(TYPEDARGS(__VA_ARGS__)) { \ return wrap_##fn(ARGS(__VA_ARGS__)); \ } WRAP(int, foo, const char*) WRAP(int, bar, const char*, const char*) WRAP(int, baz, char, int, unsigned) // -- TESTS -------------------------------------------------------------------- static_assert(CPP_ARGC() == 0); static_assert(CPP_ARGC(int) == 1); static_assert(CPP_ARGC(int, int) == 2); static_assert(CPP_ARGC(int, int, int) == 3);