C++ – Is this possible use ellipsis in macro? Can it be converted to template

cc-preprocessorloggingvisual c++

Having implemented CLogClass to make decent logging I also defined macro, but it works only with one parameter…

class CLogClass
{ 
public:
       static void DoLog(LPCTSTR sMessage, ...);
};
#define DebugLog(sMessage, x) ClogClass::DoLog(__FILE__, __LINE__, sMessage, x)

Well, it fails when called with more than 2 parameters 🙁 … Is it possible at all to avoid it? Can it be translated to templates somehow?

EDIT: Variadic macros were introduced in VS 2005 (But i'm currently in VS 2003…). Any advices?

Best Answer

You could have a MYLOG macro returning a custom functor object which takes a variable number of arguments.

#include <string>
#include <cstdarg>

struct CLogObject {

  void operator()( const char* pFormat, ... ) const {
    printf( "[%s:%d] ", filename.c_str(), linenumber );
    va_list args;
    va_start( args, pFormat );
    vfprintf( stderr, pFormat, args );
    va_end( args );
  }

  CLogObject( std::string filename, const int linenumber )
    : filename( filename ), linenumber( linenumber )
  {}
  std::string filename;
  int linenumber;
};

#define MYLOG CLogObject( __FILE__, __LINE__ )


int _tmain(int argc, _TCHAR* argv[])
{

  MYLOG( "%s, %d", "string", 5 );
  return 0;
}

Note that it's not so hard to step over to the type-safe variant touched by this answer: you don't need any variadic arguments due to the chaining effect of operator<<.

struct CTSLogObject {

  template< typename T >
  std::ostream& operator<<( const T& t ) const {
    return std::cout << "[" << filename << ":" << linenumber << "] ";
  }

  CTSLogObject( std::string filename, const int linenumber )
    : filename( filename ), linenumber( linenumber )
  {}
  std::string filename;
  int linenumber;
};
#define typesafelog CTSLogObject( __FILE__, __LINE__ )

int _tmain(int argc, _TCHAR* argv[])
{
  typesafelog << "typesafe" << ", " << 5 << std::endl;
  return 0;
}
Related Topic