引入#
在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