Frage

Nachdem CLogClass implementiert anständige Protokollierung machen ich auch Makro definiert, aber es funktioniert nur mit einem Parameter ...

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

Nun, versagt es, wenn sie mit mehr als zwei Parametern aufgerufen :( ... Ist es überhaupt möglich ist, es zu vermeiden? Kann es irgendwie Vorlagen übersetzt werden?

EDIT: Variadische Makros wurden in VS 2005 eingeführt (aber ich bin derzeit in VS 2003 ...). Irgendwelche Hinweise?

War es hilfreich?

Lösung

Sie könnten ein mylog Makro haben eine benutzerdefinierte Funktors Objekt zurückgegeben, die eine variable Anzahl von Argumenten nimmt.

#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;
}

Beachten Sie, dass es nicht so schwer ist, an die typsichere Variante zu dem Schritt über berührt von diese Antwort: . Sie nicht wegen der Verkettungs Wirkung von operator<< alle variadische Argumente benötigen

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;
}

Andere Tipps

Ihre Fragen anspricht eigentlich zwei Antworten. Sie möchten die Universal-Logging-Funktion zu tun, die wie printf funktioniert, kann aber vollständig anpassen werden. So benötigen Sie:

  • Makro eine variable Anzahl von Argumenten unter
  • Funktion eine variable Anzahl von Argumenten
  • nehmen

Hier ist Ihr Codebeispiel 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);
}

Variadische Makros wurden in C99 eingeführt, so dass es auf Compiler unterstützt C99 oder C ++ 0x funktionieren. Getestet habe ich es erfolgreich mit gcc 3.4.2 und Visual Studio 2005.

Variadische Argumente an Funktionen haben es immer schon so keine Sorge über compability hier.

Es ist wahrscheinlich möglich, es mit einiger Vorlage Meta-programmaing zu tun, aber ich habe nicht das Interesse den es angesichts der Einfachheit des Codes siehe oben.

Als letzte Anmerkung, warum statt einer Funktion eine statische Methode in einer leeren Klasse verwenden?

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);
        }
};

Kann trivialer Weise erweitert werden Zeitstempel zu schreiben, überprüfen Sie für loglevel, schreiben Datei etc.

oder, einfacher, aber weniger flexibel:

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();
        }
};

Verbrauch:

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

Ich würde dazu neigen, eine global sichtbar extern Funktion zu verwenden, anstatt ein Makro in diesem Fall, und löst die Auslassungspunkte in dieser Funktion eine va_list verwenden. Siehe meine frühere Post für ein Beispiel dafür, wie diese erreichen .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top