■はじめに
C++では、関数引数に func( LPCTSTR lpszFormat, ... ); などと書くことによって
可変長引数を扱うことができるが、マクロではできない。
マクロで可変長引数を使えたら便利なのになー、ということで、Tips を紹介する。
それはズバリ、クラスを利用するのである。クラスとマクロの複合技で実現する。
■イメージ
例えば、下記のようなファイルへ出力するマクロがあったとする。
#define PUTLOG1( fp, format, arg1 ) \
_ftprintf( fp, _T( "[%s](%d): " ) format _T( "\n" ), __FILE__, __LINE__, arg1 )
#define PUTLOG2( fp, format, arg1, arg2 ) \
_ftprintf( fp, _T( "[%s](%d): " ) format _T( "\n" ), __FILE__, __LINE__, arg1, arg2 )
#define PUTLOG3( fp, format, arg1, arg2, arg 3 ) \
_ftprintf( fp, _T( "[%s](%d): " ) format _T( "\n" ), __FILE__, __LINE__, arg1, arg2, arg3 )
これを下記のように1つのマクロで書けないか、というオハナシ。
#define PUTLOG( fp, format, ... )
/* how to */
■ソースコード
// ※下記のコードは VC++ .NET2003 で動作を確認。
class CPutLog
{
protected:
const char* m_lpszFile;
int m_nLine;
public:
CPutLog( const char* lpszFile, int nLine )
: m_lpszFile( lpszFile ), m_nLine( nLine )
{
}
void operator()( FILE* fp, LPCTSTR lpszFormat, ... ) const
{
va_list ptr;
va_start( ptr, lpszFormat );
fprintf( fp, "[%s](%d): ", m_lpszFile, m_nLine );
_vftprintf( fp, lpszFormat, ptr );
fprintf( fp, "%c", '\n' );
va_end( ptr );
}
};
#define PUTLOG CPutLog( __FILE__, __LINE__ )
これで OK! あとは使うダケ。
PUTLOG( fp, _T( "%s" ), _T( "これはテストです" ) );
PUTLOG( fp, _T( "%d + %d = %d" ), 1, 3, 4 );
プリプロセス後は次のように展開される。
CPutLog( __FILE__, __LINE__ )( fp, _T( "%s" ), _T( "これはテストです" ) );
CPutLog( __FILE__, __LINE__ )( fp, _T( "%d + %d = %d" ), 1, 3, 4 );
CPutLog( __FILE__, __LINE__ ) で CPutLog 型の一時オブジェクトが作成され、
その一時オブジェクトに対し、operator() 呼び出しがされる。
■出力例
[c:\xxxx\test.cpp](296): これはテストです
[c:\xxxx\test.cpp](297): 1 + 34