endlをオーバーライドします。

ストリームクラスのカスタマイズをしようとした際に、endl や ends をフックしたいと思いました。現段階では、filebuf の sync() をオーバーロードするか、endl をフックする方がいいのかわからないので、一時的にSVNにコミットしておいて、試している最中です。SVNで戻すのも煩わしいのでメモしておきます。

#include <iomanip>
#include <fstream>

class mystream : public std::ofstream
{
public:
  mystream() : std::ofstream() {}
  
  /*
  * 挿入演算子(<<)をフックします。
  *   戻り値をこのクラスへの参照にするために、必要なフックです。
  */
  template<typename _unknowntype>
  friend mystream& operator << ( mystream& of, _unknowntype& rhs )
  {
    std::operator <<( of, rhs );
    return of;
  }

  /*
  * setw() などの引数付マニピュレータをフックします。
  *   戻り値をこのクラスへの参照にするために、必要なフックです。
  */
  template<class _Arg> 
    friend  mystream& operator<<( mystream& _Ostr, const std::_Smanip<_Arg>& _Manip )
  {
    (*_Manip._Pfun)(_Ostr, _Manip._Manarg);
    return (_Ostr);
  }

  /*
  * 引数無しのマニピュレータをフックします。
  *   このクラス用の endl や ends などが動くための措置です。
  */
  mystream& operator<<( mystream& (__cdecl *_Pfn)(mystream&) )
  {
    return ((*_Pfn)(*this));
  }

  // endl (引数無しのマニピュレータ)をフックします。
  friend mystream& endl( mystream& os )
  {
    std::endl(os);
    return os;
  }

  // ends (引数無しのマニピュレータ)をフックします。
  friend mystream& ends( mystream& os )
  {
    std::ends(os);
    return os;
  }
};

int main( int argc, char* argv[] )
{
  mystream logger;
  logger.open("abc.log",std::ios_base::app);

  logger <<"123456789" <<endl;
  logger <<"ABC" <<ends;
  logger <<"DEF" <<endl;
  logger <<std::setw(12) <<"123456789" <<endl;
	
  logger.close();
  return 0;
}

実行結果をmeadowでみると、NULL(0x00)が^@と表示されるので、

123456789
ABC^@DEF
   123456789

という感じです。ファイルをダンプしてみると、次のようになります。

$ od -t x1 abc.log
0000000 31 32 33 34 35 36 37 38 39 0d 0a 41 42 43 00 44
0000020 45 46 0d 0a 20 20 20 31 32 33 34 35 36 37 38 39
0000040 0d 0a

これ以外にもフックする必要があるかも知れません。追求は棚上げにします。