用表达式包装可变参数宏中的每个元素
Wrap each element in variadic macro with an expression
问题:
我想写一个可变参数宏
#define WRAP(token, ...)
当使用令牌和 N 个参数调用时
WRAP(decltype, a, b, c)
将扩展为包含在令牌中的以逗号分隔的参数列表
decltype(a), decltype(b), decltype(c)
这样我就可以编写如下内容:
#define MACRO(...) \
Class< WRAP(decltype, __VA_ARGS__) >::Function();
如果我这样调用它:
MACRO(a, b, c)
它会导致:
Class<decltype(a), decltype(b), decltype(c)>::Function(0;
我不知道如何实现。可能吗?也许用 BOOST_PP
或类似的东西?
动机:
我有一个用于记录的宏:
#define LOG(fmt, ...) \
logger::instance().push(__FUNCTION__, fmt, __VA_ARGS__);
我有一个可变参数 class 模板,它能够验证参数是否匹配提供的格式字符串
template<typename... Ts>
struct Format
{
template<std::size_t N>
static constexpr bool check(const char (&fmt)[N], std::size_t n);
};
如果我用固定数量的参数定义一个宏,我可以调用我的格式检查函数:
#define LOG(fmt, a) \
static_assert(Format<decltype(a1)>::check(fmt, 0), ""); \
logger::instance().push(__FUNCTION__, fmt, a);
但是,如果我使用可变参数宏,这将不适用于超过 1 个参数:
#define LOG(fmt, ...) \
static_assert(Format<decltype(__VA_ARGS__)>::check(fmt, 0), ""); \
logger::instance().push(__FUNCTION__, fmt, __VA_ARGS__);
那是因为decltype(__VA_ARGS__)
显然是无效语法。
要修复它,我需要将 __VA_ARGS__
扩展为 decltype(a1), decltype(a2), decltype(a3)
可变函数模板?
我尝试使用 constexpr
可变函数模板来实现此目的,但我无法将 fmt
传递给 static_assert
,因为它此时不再是字符串文字点数:
template<size_t N, typename... Ts>
constexpr void check(const char (&fmt)[N], const Ts&...)
{
static_assert(Format<Ts...>::check(fmt, 0), "");
}
正在尝试调用此检查函数
check("%s", "hello world");
编译失败:
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
用Boost.PP很简单:
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/variadic/to_seq.hpp>
#define COMMA_SEP(r, token, i, e) BOOST_PP_COMMA_IF(i) token(e)
#define WRAP(token, ...) BOOST_PP_SEQ_FOR_EACH_I(COMMA_SEP, token, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
编辑:如果__VA_ARGS__
为空,上述方法将不起作用,解决方法请参考this solution,但注意解决方法不适用于 MSVC,因为它们的预处理器不符合标准,如果你想支持 MSVC,只需使用 BOOST_PP_IS_EMPTY
代替 ISEMPTY
。
问题:
我想写一个可变参数宏
#define WRAP(token, ...)
当使用令牌和 N 个参数调用时
WRAP(decltype, a, b, c)
将扩展为包含在令牌中的以逗号分隔的参数列表
decltype(a), decltype(b), decltype(c)
这样我就可以编写如下内容:
#define MACRO(...) \
Class< WRAP(decltype, __VA_ARGS__) >::Function();
如果我这样调用它:
MACRO(a, b, c)
它会导致:
Class<decltype(a), decltype(b), decltype(c)>::Function(0;
我不知道如何实现。可能吗?也许用 BOOST_PP
或类似的东西?
动机:
我有一个用于记录的宏:
#define LOG(fmt, ...) \
logger::instance().push(__FUNCTION__, fmt, __VA_ARGS__);
我有一个可变参数 class 模板,它能够验证参数是否匹配提供的格式字符串
template<typename... Ts>
struct Format
{
template<std::size_t N>
static constexpr bool check(const char (&fmt)[N], std::size_t n);
};
如果我用固定数量的参数定义一个宏,我可以调用我的格式检查函数:
#define LOG(fmt, a) \
static_assert(Format<decltype(a1)>::check(fmt, 0), ""); \
logger::instance().push(__FUNCTION__, fmt, a);
但是,如果我使用可变参数宏,这将不适用于超过 1 个参数:
#define LOG(fmt, ...) \
static_assert(Format<decltype(__VA_ARGS__)>::check(fmt, 0), ""); \
logger::instance().push(__FUNCTION__, fmt, __VA_ARGS__);
那是因为decltype(__VA_ARGS__)
显然是无效语法。
要修复它,我需要将 __VA_ARGS__
扩展为 decltype(a1), decltype(a2), decltype(a3)
可变函数模板?
我尝试使用 constexpr
可变函数模板来实现此目的,但我无法将 fmt
传递给 static_assert
,因为它此时不再是字符串文字点数:
template<size_t N, typename... Ts>
constexpr void check(const char (&fmt)[N], const Ts&...)
{
static_assert(Format<Ts...>::check(fmt, 0), "");
}
正在尝试调用此检查函数
check("%s", "hello world");
编译失败:
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
用Boost.PP很简单:
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/variadic/to_seq.hpp>
#define COMMA_SEP(r, token, i, e) BOOST_PP_COMMA_IF(i) token(e)
#define WRAP(token, ...) BOOST_PP_SEQ_FOR_EACH_I(COMMA_SEP, token, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
编辑:如果__VA_ARGS__
为空,上述方法将不起作用,解决方法请参考this solution,但注意解决方法不适用于 MSVC,因为它们的预处理器不符合标准,如果你想支持 MSVC,只需使用 BOOST_PP_IS_EMPTY
代替 ISEMPTY
。