Problem:
I'm looking to write a variadic macro
#define WRAP(token, ...)
which, when called with a token and N arguments
WRAP(decltype, a, b, c)
will expand into a comma-separated list of the arguments wrapped in the token
decltype(a), decltype(b), decltype(c)
This would allow me to write something like the following:
#define MACRO(...) \
Class< WRAP(decltype, __VA_ARGS__) >::Function();
If I call it as follows:
MACRO(a, b, c)
it would result in:
Class<decltype(a), decltype(b), decltype(c)>::Function(0;
I have no idea how to achieve this. Is it possible? Perhaps with BOOST_PP or some such?
Motivation:
I have a macro for logging:
#define LOG(fmt, ...) \
logger::instance().push(__FUNCTION__, fmt, __VA_ARGS__);
I have a variadic class template which is able to verify the arguments match the provided format string
template<typename... Ts>
struct Format
{
template<std::size_t N>
static constexpr bool check(const char (&fmt)[N], std::size_t n);
};
If I define a macro with a fixed number of arguments I can call my format checking function:
#define LOG(fmt, a) \
static_assert(Format<decltype(a1)>::check(fmt, 0), ""); \
logger::instance().push(__FUNCTION__, fmt, a);
However, if I use a variadic macro, this won't work for more than 1 argument:
#define LOG(fmt, ...) \
static_assert(Format<decltype(__VA_ARGS__)>::check(fmt, 0), ""); \
logger::instance().push(__FUNCTION__, fmt, __VA_ARGS__);
That's because decltype(__VA_ARGS__) is obviously invalid syntax.
to fix it, I need to expand __VA_ARGS__ into decltype(a1), decltype(a2), decltype(a3)
Variadic function template?
I have tried to achieve this using a constexpr variadic function template, but I am unable to pass fmt to a static_assert as it is no longer a string literal at this point:
template<size_t N, typename... Ts>
constexpr void check(const char (&fmt)[N], const Ts&...)
{
static_assert(Format<Ts...>::check(fmt, 0), "");
}
Trying to call this check function
check("%s", "hello world");
fails to compile:
main.cpp:216:46: in constexpr expansion of ‘Format<T, Ts ...>::check<7ul>((* & fmt), 0ul)’
main.cpp:216:5: error: ‘fmt’ is not a constant expression
Format<>. - Pradhanfmtto a function, such that it's type isconst char (&fmt)[N], I cannot use that in astatic_assert: The following fails to compile:template<size_t N, typename... Ts> constexpr void check(const char (&fmt)[N], const Ts&...) { static_assert(Format<Ts...>::check(fmt, 0), ""); }with error‘fmt’ is not a constant expression- Steve Lorimer