如何使用宏打印可变数量的参数
How to print a variable number of parameters with a macro?
我想定义一个具有可变参数数的宏,该宏打印每个给定参数的名称和值。
例如:
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];}}
#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调用中包含什么间距(或不包含),都将在输出中镜像。
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
不是一个理想的解决方案,但:
宏本身可以采用固定数量的参数,但每个参数都可以是一个带括号的列表(即使它只是一个文本字符串)。
void function_taking_varargs(...);
#define SLIGHTLY_BETTER(x)
function_taking_varargs x
SLIGHTLY_BETTER((a, b, c));
这个在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
这是一个活生生的例子。
如果您使用的是支持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;
}
- 何时应在构造函数参数中使用 const C++?
- 概念可以与模板模板参数一起使用吗?
- 如何在模板参数中使用 std::is_pod?
- 在模板参数中使用 {} 在 type_trait{} 中时,其作用是什么<T>?
- 可变参数模板参数转发使用逗号运算符
- 在模板函数参数中使用 std::bind
- 函数参数中使用的复杂文字'i'
- 设置内核参数时使用CL_INVALID_ARG_SIZE
- 为什么当我尝试将priority_queue与参数一起使用作为指向结构的指针时会弹出错误
- 标准::原子::compare_exchange与两个memory_order参数一起使用的真实示例
- 如何在 C++ 中将 typedef 与类初始值设定项参数一起使用?
- 在命令行参数中使用引号
- 对可变参数模板使用 const 参数
- SFINAE 和模板函数实例化:为什么在启用了 SFINAE 类型的函数参数中使用模板参数时无法推断模板参数?
- 在简单地移动参数时使用函数模板参数的优点
- 如何切片可变参数模板参数并使用它们?
- 我可以将"token pasting operator"与"const"模板参数一起使用吗?
- 哪个强制转换应与模板类参数一起使用,dynamic_cast或reinterpet_cast?
- 在模板参数中使用 ref<>?
- 保留短 lambda 用作函数的中间参数,使用 clang 格式保持不变