c++ - 用表达式包装可变参数宏中的每个元素

标签 c++ c++11 macros c-preprocessor boost-preprocessor

问题:

我想写一个可变参数宏

#define WRAP(token, ...) 

当使用一个标记和 N 个参数调用时

WRAP(decltype, a, b, c)

将扩展为包含在 token 中的以逗号分隔的参数列表

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

我有一个可变类模板,它能够验证参数是否匹配提供的格式字符串

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 .

关于c++ - 用表达式包装可变参数宏中的每个元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29224493/

相关文章:

c++ - 将 CGAL 和 BOOSt 链接到 qt-creator 项目

c++ - 带 map 的 Boost::multi_index

c++ - move 构造函数和初始化列表

c++ - undefined reference

c++ - 将对 boost 数组的引用传递给类

c++ - std::forward_list -- 用存储的迭代器删除

c++ - 来自 Essential COM 的 BASE_OFFSET 宏

c++ - 在 C/C++ 中实现 UNUSED 宏的通用编译器独立方式

c++ - 如何标记粘贴号码?

c++ - 函数调用中的段错误