2

第一个工作代码:

#include <iostream>

// NOTE: requires compiler which has __PRETTY_FUNCTION__, like gcc or clang
#define DUMP(v) std::cerr << __PRETTY_FUNCTION__ << ':' << __LINE__ << ':' << #v << "='" << (v) << "'\n"

int main(int argc) {

    DUMP(argc);
    DUMP(argc+1);
    return 0;
}

这给出了标准错误输出(gcc):

int main(int):8:argc='1'
int main(int):9:argc+1='2'

现在我想要一个带有任意数量参数的可变参数宏,例如

DUMP(argc, argc+1);可以工作,输出如下:

int main(int):8:argc='1',argc+1='2'


但我还没有想出一个好的解决方案。这甚至可以用宏来实现吗?如果不是,那么模板或宏和模板的组合如何?如果需要,C++11 和 Boost 都可以,如果没有标准方法,解决方案可以是gcc特定的。寻找实际代码,使可变参数 DUMP 像上面描述的那样工作,或者至少显示等效信息。

4

2 回答 2

3

使用Boost.PP,你可以这样写:

#define DUMP_EACH(r, data, v) std::cerr << __PRETTY_FUNCTION__ << ':' << __LINE__ << ':' << #v << "='" << (v) << "'\n"
#define DUMP(...) BOOST_PP_SEQ_FOR_EACH(DUMP_EACH, ~, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))

您还需要-DBOOST_PP_VARIADICS=1在编译时添加。如果您不想使用 boost,您可以编写一个简单的FOR_EACH宏来迭代每个参数,如下所示:

/* This counts the number of args */
#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1)

/* This will let macros expand before concating them */
#define PRIMITIVE_CAT(x, y) x ## y
#define CAT(x, y) PRIMITIVE_CAT(x, y)

/* This will call a macro on each argument passed in */
#define FOR_EACH(macro, ...) CAT(FOR_EACH_, NARGS(__VA_ARGS__))(macro, __VA_ARGS__)
#define FOR_EACH_1(m, x1) m(x1)
#define FOR_EACH_2(m, x1, x2) m(x1) m(x2)
#define FOR_EACH_3(m, x1, x2, x3) m(x1) m(x2) m(x3)
#define FOR_EACH_4(m, x1, x2, x3, x4) m(x1) m(x2) m(x3) m(x4)
#define FOR_EACH_5(m, x1, x2, x3, x4, x5) m(x1) m(x2) m(x3) m(x4) m(x5)
#define FOR_EACH_6(m, x1, x2, x3, x4, x5, x6) m(x1) m(x2) m(x3) m(x4) m(x5) m(x6)
#define FOR_EACH_7(m, x1, x2, x3, x4, x5, x6, x7) m(x1) m(x2) m(x3) m(x4) m(x5) m(x6) m(x7)
#define FOR_EACH_8(m, x1, x2, x3, x4, x5, x6, x7, x8) m(x1) m(x2) m(x3) m(x4) m(x5) m(x6) m(x7) m(x8)

然后你可以像这样定义你的转储宏:

#define DUMP_EACH(v) std::cerr << __PRETTY_FUNCTION__ << ':' << __LINE__ << ':' << #v << "='" << (v) << "'\n"
#define DUMP(...) FOR_EACH(DUMP_EACH, __VA_ARGS__)
于 2013-05-18T16:32:57.077 回答
1

好的。这不是很好。但它可以工作,最多达到预先指定的参数数量(我在 4 时变得懒惰)。它从这里被大量扯掉(说真的,点击并投票)。它使用从字面上扩展预先写好的列表前面的参数的技巧,从后面的固定位置拉出正确的数字。然后它通过附加数字来调用正确的宏名称。清除?没有!这是代码:

#include <iostream>

// Pretty normal macro tricks

#define STRINGIZE(a) STRINGIZE1(a)
#define STRINGIZE1(a) STRINGIZE2(a)
#define STRINGIZE2(a) #a

#define CONCAT(a, b)  CONCAT1(a, b)
#define CONCAT1(a, b) CONCAT2(a, b)
#define CONCAT2(a, b) a##b

// Faux-recursively dump all the arguments

#define DUMP_1(first) std::cout << STRINGIZE(first) << "='" << first << "'\n";

#define DUMP_2(first, ...) \
do {\
    std::cout << STRINGIZE(first) << "='" << first << "': ";\
    DUMP_1(__VA_ARGS__);\
} while (false)

#define DUMP_3(first, ...) \
do {\
    std::cout << STRINGIZE(first) << "='" << first << "': ";\
    DUMP_2(__VA_ARGS__);\
} while (false)

#define DUMP_4(first, ...) \
do {\
    std::cout << STRINGIZE(first) << "='" << first << "': ";\
    DUMP_3(__VA_ARGS__);\
} while (false)


// Count the arguments

// Construct the forward/backward list:
#define COUNT_ARGS(...)  COUNT_ARGS_(__VA_ARGS__, RSEQ())
// Forward the list on (macro pain):
#define COUNT_ARGS_(...) COUNT_ARGS_N(__VA_ARGS__)
// The n+1th element is the count (predetermined to support up to n)
#define COUNT_ARGS_N(_1, _2, _3, _4, N, ...) N
#define RSEQ() 4, 3, 2, 1


// This just calls the correct DUMP_#
#define DUMP_(N, ...) CONCAT(DUMP_, N)(__VA_ARGS__)
// Start the line, and start the "recursion"
#define DUMP(...) \
do {\
    std::cout << __PRETTY_FUNCTION__ << ':' << __LINE__ << ": "; \
    DUMP_(COUNT_ARGS(__VA_ARGS__), __VA_ARGS__); \
} while (false)

int main(int argc, char* argv[])
{
    DUMP(argc);

    int i = 10;
    const char str[] = "Hello, world";
    DUMP(i, str);

    return 0;
}

输出:

$ ./a.out 
int main(int, char**):49: argc='1'
int main(int, char**):52: i='10': str='Hello, world'

编辑:这是计数部分(困难部分)的简单版本:

#include <iostream>

#define COUNT_ARGS(...)  COUNT_ARGS_(__VA_ARGS__, RSEQ())
#define COUNT_ARGS_(...) COUNT_ARGS_N(__VA_ARGS__)
#define COUNT_ARGS_N(_1, _2, _3, _4, _5, _6, N, ...) N
#define RSEQ() 6, 5, 4, 3, 2, 1

int main()
{
    std::cout << COUNT_ARGS(a, b) << '\n';
    std::cout << COUNT_ARGS(a, b, c, d) << '\n';

    return 0;
}

输出:

1
2

这是如何运作的?

好吧,就像我一样,您将其设置为最多 6 个。它构造了一个长列表,并提取了第 7 个元素。这总是包含正确的值,因为它从中提取该值的列表是通过将用户提供的所有参数放在后面,然后是一个 count in reverse来构造的。

因此,通过添加另一个参数,您可以将计数向后推 1,并从中获得更高的数字。看这张图片: 在此处输入图像描述

于 2013-05-09T15:32:36.050 回答