Pergunta

Tendo implementado CLogClass para fazer o registo decente Eu também definido macro, mas funciona apenas com um parâmetro ...

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

Bem, ele falhar quando chamado com mais de 2 parâmetros :( ... É possível em tudo para evitá-lo? Pode ser traduzido para modelos de alguma forma?

EDIT: macros variádicos foram introduzidos no VS 2005 (mas eu estou atualmente no VS 2003 ...). Qualquer conselhos?

Foi útil?

Solução

Você poderia ter um macro mylog retornando um objeto functor personalizada que leva um número variável de argumentos.

#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 que não é tão difícil de passar por cima para a variante de tipo seguro tocado por esta resposta : você não precisa de quaisquer argumentos variádicos devido ao efeito de encadeamento de 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;
}

Outras dicas

As suas perguntas realmente agrada a duas respostas. Você quer fazer a função de registro universal, que funciona como printf, mas pode ser totalmente customize. Então, você precisa:

  • macro tomando um número variável de argumentos
  • função de tomar um número variável de argumentos

Aqui é o seu exemplo de código adatapted:

#include <stdio.h>
#include <stdarg.h>


class CLogClass
{
public:
    static void DoLogWithFileLineInfo( const char * fmt, ... )
    {
        va_list ap;
        va_start( ap, fmt );
        vfprintf( stderr, fmt, ap );
        va_end( ap );
    }

};


#define MYLOG(format, ...) CLogClass::DoLogWithFileLineInfo("%s:%d " format , __FILE__, __LINE__, __VA_ARGS__)

int main()
{
    MYLOG("Hello world!\n", 3); // you need at least format + one argument to your macro
    MYLOG("%s\n", "Hello world!");
    MYLOG("%s %d\n", "Hello world!", 3);
}

macros variádicos foram introduzidas no C99, por isso vai trabalhar em compiladores apoio C99 ou C ++ 0x. Eu testei com sucesso com gcc 3.4.2 e Visual Studio 2005.

argumentos variádicos para funções foram lá para sempre assim que nenhuma preocupação sobre compability aqui.

É provavelmente possível fazê-lo com algum modelo de meta-programmaing mas eu não vejo o interesse de que, dada a simplicidade do código acima.

Como uma última nota, por que usar um método estático em uma classe vazia em vez de uma função?

class Log {
    stringstream buffer;
    public:
        class Proxy {
            public:
                Proxy(Log& p) : parent(p) {}
                template<class T>
                Proxy& operator,(T const& t) {
                    parent.buffer << t;
                    return *this;
                }
                ~Proxy() {
                    parent.buffer << endl;
                    cout << parent.buffer.str();
                    parent.buffer.str("");
                }
            private:
                CLog& parent;
        };

        template<class T>
        Proxy operator<<(T const& t) {
            buffer << t;
            return Proxy(*this);
        }
};

Pode ser trivialmente estendida a data e hora de gravação, verifique se há loglevel, escreva para arquivo, etc.

Ou, mais simplesmente, mas menos flexível:

class Log {
    public:
        class Proxy {
            public:
                template<class T>
                Proxy& operator,(T const& t) {
                    cout << t;
                    return *this;
                }
                ~Proxy() {
                    cout << endl;
                }
        };

        template<class T>
        Proxy operator<<(T const& t) {
            cout << t;
            return Proxy();
        }
};

Uso:

Log log;
void f() {
     log << "hey, my age is ", age;
}

Eu tenderia a usar uma função externa globalmente visível em vez de uma macro neste exemplo, e resolver as reticências nessa função usando um va_list. Veja meu post anterior para um exemplo sobre como conseguir isso .

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top