可变参数模板的应用
引入
在C++中经常打印变量来调试代码,但无论是printf还是cout总是很麻烦:
printfint a = 1; float b = 2.0; char c = 'c'; printf("a = %d, b = %f, c = %c", a, b, c);coutint 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