引入#
在C++
中经常打印变量来调试代码,但无论是printf
还是cout
总是很麻烦:
-
printf
int a = 1; float b = 2.0; char c = 'c'; printf("a = %d, b = %f, c = %c", a, b, c);
-
cout
int a = 1; float b = 2.0; char c = 'c'; std::cout << "a = " << a << ", b = " << b << ", c = " << c << '\n';
可变参数宏#
可变参数宏是C99
引入的一个特性,C++11
开始支持。
#define def_name(...) def_body(__VA_ARGS__)
可变参数模板#
C++11
允许模板定义有任意类型任意数量的模板参数(包括 $0$ 个模板参数)。
template<typename... Values> class tuple;
如果不希望有 $0$ 个模板实参,可以如下声明:
template<typename First, typename... Rest> class tuple;
可变参数模板适用于函数模板,例如printf
函数的实现:
template<typename... Args>
void printf(const std::string &str_format, Args... args);
参数包的展开#
- 对于模板函数
- 递归展开
// 递归终止函数 void print() {} template<typename T, typename... Args> void print(T head, Args... args) { std::cout << head << (sizeof...(args) > 0 ? ", " : ""); print(args...); }
- 逗号表达式展开:这种方式有点繁琐,不太好理解,不推荐
- 对于模板类
- 递归展开
- 继承展开
宏运算符#
-
#
:将宏参数转换为字符串#include <stdio.h> #define stringer( x ) printf( #x "\n" ) int main() { stringer( In quotes in the printf function call ); stringer( "In quotes when printed to the screen" ); stringer( "This: \" prints an escaped double quote" ); }
使用
gcc -E
预处理之后,得到如下结果int main() { printf("In quotes in the printf function call" "\n"); printf("\"In quotes when printed to the screen\"" "\n"); printf("\"This: \\\" prints an escaped double quote\"" "\n"); }
-
#@
:将参数用单引号括起来,作为一个字符处理#define makechar(x) #@x c = makechar(b);
预处理之后得到:
c = 'b';
-
##
:将两个独立的token
连接在一起#define paster(n) printf("token" #n " = %d", token##n) int token9 = 9; paster(9);
预处理之后得到:
printf("token9 = %d", token9);
实现DBG
宏#
掌握了以上技能,我们就可以实现一个简单的调试宏:
#include <iostream>
#include <string>
template <typename T>
void _DBG(const char *s, T t) {
std::cout << s << "=" << t << '\n';
}
template <typename T, typename... Args>
void _DBG(const char *s, T t, Args... args) {
while (*s != ',')
std::cout << *s++;
std::cout << "=" << t << ",";
_DBG(s + 1, args...);
}
#define DBG(...) _DBG(#__VA_ARGS__, __VA_ARGS__)
int main() {
int a = 1;
float b = 2.0;
char c = 'c';
std::string d = "def";
DBG(a, b, c, d);
return 0;
}
上面的代码输出:
a=1, b=2, c=c, d=def