operator<<をオーバーロードして任意書式

シリアル通信のプログラムなどでは,多くの場合 unsigned char の配列にデータを保存する.このようなデータを16進数で標準出力に表示する場合, operator<< をオーバーロードすると便利だ.しかし,単純に unsigned char* に対してオーバーロードすると,オリジナルの (iostream で宣言されているのと) コンフリクトする.以下では,既にある operator<< と整合性を取りつつ,任意に書式設定する方法について解説する.

アイディア

基本的なアイディアは,

  1. 出力対象の変数 (上の例では unsigned char*) を含む構造体を定義し,コンストラクタで出力対象の変数を代入できるようにする
  2. operator<< を定義した構造体に対してオーバーロードする

というもの.ここで定義する構造体のコンストラクタに,書式設定のパラメタを持たせることもできる.

サンプル

次のプログラムでは,unsigned char* の変数を含む構造体 echo_uschar を定義し,operator<< を echo_uschar に対してオーバーロードしている.

#include <iomanip>
using namespace std;

struct echo_uschar
{
  const unsigned char *s;
  int n;
  const char *delim;
  echo_uschar(const unsigned char *_s,int _n,const char *_delim=" ")
    : s(_s), n(_n), delim(_delim) {};
};
ostream& operator<< (ostream &lhs, const echo_uschar &rhs)
{
  for (int i(0);i<rhs.n;++i)
    lhs<<rhs.delim<<setw(2)<<setfill('0')<<hex<<static_cast<int>(rhs.s[i])<<dec;
  return lhs;
};

int main(int argc,char**argv)
{
  unsigned char data[]= {0x01,0x12,0x33,0x28,0x00};
  const int N= sizeof(data)/sizeof(data[0]);
  cout<<"data= "<<echo_uschar(data,N)<<endl;
  return 0;
}

出力結果:

data=  01 12 33 28 00

main で

  cout<<"data= "<<echo_uschar(data,N,"-")<<endl;

とすれば,-で区切れる.

同じ変数型に対して異なる書式を持たせた operator<< を複数作りたい場合は,このメソッドがベストだと思います.