【问题标题】:How to print a variable number of parameters with a macro?如何使用宏打印可变数量的参数?
【发布时间】:2014-05-22 18:54:43
【问题描述】:

我想定义一个带有可变数量参数的宏,它打印每个给定参数的名称和值。

例如:

MACRO(x) 将打印 x = 123 MACRO(x,y) 将打印 x,y = 123,666

一个更好的宏会更具可读性

BETTER_MACRO(x,y) 将打印 x = 123, y = 666

对于一个变量,我可以使用:

#define MACRO(...) cout << #__VA_ARGS__ << " = " << __VA_ARGS__ << endl;

更多,它不起作用。

通过这种方式,我想到了一些辅助问题。

1) 如何获取给宏的变量个数? 2) 如何访问每个参数?

天真地猜测,我们可以回答这两个问题。

然后我们希望通过以下方式定义宏。

#define BETTER_MACRO(...) {for (int i=0;i<=nb_variables;i++) {cout << #var[i] << var[i];}}

【问题讨论】:

标签: c++ c-preprocessor variadic-macros


【解决方案1】:
#define MACRO(...) function(#__VA_ARGS__, __VA_ARGS__)

// base case for template recursion when one argument remains
template <typename Arg1>
void function(const char* name, Arg1&& arg1)
{
    std::cout << name << " = " << arg1 << std::endl;
}

// recursive variadic template for multiple arguments
template <typename Arg1, typename... Args>
void function(const char* names, Arg1&& arg1, Args&&... args)
{
    const char* comma = strchr(names + 1, ',');
    std::cout.write(names, comma - names) << " = " << arg1;
    function(comma, args...);
}

上面有一些异想天开的属性,即您在 MACRO 调用中包含的任何间距(或不包含)都将反映在输出中。

【讨论】:

  • 我尝试了您的解决方案,这与我的预期最接近。当我将宏应用于 2 个以上的参数时,我注意到了一个问题。 MACRO(a,b,c) 打印出 a=1 =2,b,c=3 而不是 a=1,b=2,c=3。我还不知道如何解决它。无论如何,感谢帮助我的人。这个社区很棒。 :-)
  • 倒数第二行。将comma 替换为comma + 1
  • @captain_flammy:对此感到抱歉,我以一种我发现更好的方式修复了它:在对strchr 的调用中将names 加1。我认为这使它始终有效。
  • 很好,除了你糟糕的函数命名。还在那里扔一些通用参考,好吗?
  • @LightnessRacesinOrbit:我将函数命名为函数,因为 OP 将宏命名为 MACRO。我总是尝试匹配当地的惯例! ;-) 至于通用参考,我已经添加了它们(希望是正确的)。
【解决方案2】:

如果您使用的是支持 C++11 的编译器或具有 C++03 非标准扩展的编译器:

有两个宏和一个模板:

#include <iostream>

struct None {};

template <typename T>
struct Log
{
    static void write(const char* name, const T& value) {
        std::clog << name << " = " << value << '\n';
    }
};

template<>
struct Log<None>
{
    static void write(const char*, const None&) {}
};

#define LOG_VALUE_DETAIL(A, B, C, D, E, ...) do { \
    Log<decltype(A)>::write(#A, A); \
    Log<decltype(B)>::write(#B, B); \
    Log<decltype(C)>::write(#C, C); \
    Log<decltype(D)>::write(#D, D); \
    Log<decltype(E)>::write(#E, E); \
} while(0)

#define LOG_VALUE(...) LOG_VALUE_DETAIL(__VA_ARGS__, None(), None(), None(), None(), None())

inline int f() { return 3; }

int main()
{

    int a = 0;
    int b = 1;
    int c = 2;
    LOG_VALUE(a, b, c, f());
    return 0;
}

【讨论】:

    【解决方案3】:

    1) 如何获取给宏的变量个数?

    您可以使用类似这样的方法来计算元素:(具有硬编码限制):

    #define COUNT_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...)    N
    #define COUNT(...)   COUNT_N(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
    // Warning: COUNT() return 1 (as COUNT(A)) :-/
    

    2) 如何访问每个参数?

    /* args */
    #define ARG(N, ...) ARG_##N(__VA_ARGS__)
    
    #define ARG_1(a, ...) a
    #define ARG_2(a, b,...) b
    #define ARG_3(a, b, c, ...) c
    #define ARG_4(a, b, c, d, ...) d
    #define ARG_5(a, b, c, d, e, ...) e
    #define ARG_6(a, b, c, d, e, f, ...) f
    #define ARG_7(a, b, c, d, e, f, g, ...) g
    #define ARG_8(a, b, c, d, e, f, g, h, ...) h
    

    【讨论】:

    • 顺便说一下,Boost 已经这样做了多达...256? BOOST_PP_VARIADIC_SIZE.
    【解决方案4】:

    这个在 C++11 之前工作,没有丑陋的可变参数函数。相反,它使用丑陋的宏,这至少会产生编译时错误。调用语法有点不同,但并没有太多。我尝试寻找类似SEQ_ENUM 的东西,但是使用宏,却找不到任何东西。

    首先,我们将制作自定义的打印宏:

    #define PRINT_ONE(elem) BOOST_PP_STRINGIZE(elem) " = " << elem
    #define PRINT_ONE_COMMA(r, data, elem) BOOST_PP_STRINGIZE(elem) " = " << elem << ", " <<
    

    接下来,一些打印实用程序:

    #define LAST(seq) BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(seq)), seq)
    #define REST(seq) BOOST_PP_SEQ_SUBSEQ(seq, 0, BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(seq)))
    

    最后,我们可以遍历并打印:

    #define PRINT(seq) std::cout << BOOST_PP_SEQ_FOR_EACH(PRINT_ONE_COMMA, _, REST(seq)) PRINT_ONE(LAST(seq)) << '\n';
    

    用法如下:

    PRINT((var1)(var2)(var3)) // var1 = 5, var2 = 3, var3 = 7
    

    这是live example

    【讨论】:

      【解决方案5】:

      不是一个理想的解决方案,但是:

      宏本身可以接受固定数量的参数,但每个参数都可以是一个带括号的列表(即使它只是一个文本字符串)。

       void function_taking_varargs(...);
      
       #define SLIGHTLY_BETTER(x) \
            function_taking_varargs x
      
      
       SLIGHTLY_BETTER((a, b, c));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-15
        • 1970-01-01
        • 2021-01-12
        • 1970-01-01
        • 2012-09-02
        • 2014-10-01
        • 1970-01-01
        相关资源
        最近更新 更多