0xe3aad

0xe3aad

可変引数テンプレートの利用

導入#

デバッグコードを作成する際には、C++では変数を出力することがよくありますが、printfcoutを使用すると手間がかかります:

  • 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 

参考文献#

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。