導入#
デバッグコードを作成する際には、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"); }
-
#@
:引数をシングルクォートで囲んで、1 文字として処理する#define makechar(x) #@x c = makechar(b);
プリプロセス後は次のようになります:
c = 'b';
-
##
:2 つの独立した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