// 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);