With hard coded limit, you might do
#define TAKE_11(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define COUNT(...) TAKE_11(__VA_ARGS__ __VA_OPT__(,) 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define IDENTITY(N) N
#define APPLY(macro, ...) IDENTITY(macro(__VA_ARGS__))
#define F_0(F)
#define F_1(F, a) F(a)
#define F_2(F, a, b) F(a), F(b)
#define F_3(F, a, b, c) F(a), F(b), F(c)
#define F_4(F, a, b, c, d) F(a), F(b), F(c), F(d)
#define F_5(F, a, b, c, d, e) F(a), F(b), F(c), F(d), F(e)
#define F_6(F, a, b, c, d, e, f) F(a), F(b), F(c), F(d), F(e), F(f)
#define F_7(F, a, b, c, d, e, f, g) F(a), F(b), F(c), F(d), F(e), F(f), F(g)
#define F_8(F, a, b, c, d, e, f, g, h) F(a), F(b), F(c), F(d), F(e), F(f), F(g), F(h)
#define DISPATCH(N) F_ ## N
#define FOR_EACH(F, ...) IDENTITY(APPLY(DISPATCH, COUNT(__VA_ARGS__)))(F __VA_OPT__(,) __VA_ARGS__)
#define MAKE_PAIR(x) std::make_pair(#x, x)
#define WRITE_LOG_WITH_PARAMS(logger, messageString, logLevel, ...)
(logger).PrintLogMessage(LogMessage(messageString, logLevel, __LINE__,
filesystem::path(__FILE__).filename().string(),
__FUNCTION__, __TIMESTAMP__, ThisThreadGetIdString(), std::make_tuple(FOR_EACH(MAKE_PAIR __VA_OPT__(,) __VA_ARGS__))))
Demo
Note: __VA_OPT__
(C++20) is to handle empty ...
Previously, you cannot reliably handle that case (there are extension from compiler).
You can replace each __VA_OPT__(x)
by x
and doesn't handle empty case.