Actualmente, nuestra base de código tiene una gran cantidad de código que se parece a lo siguiente:

void log(int level, const char *msg) {
    // logLevel is some global int defining which messages to log
    if (level <= logLevel) {
        cout << msg << endl;
    }
}

...

int someNum = 3;
if (1 <= logLevel) {
    char msg[200];
    sprintf(msg, "Some format %d", someNum);
    log(1, msg);
}

Estamos usando Visual Studio 2008 y, por lo tanto, no podemos usar ninguna característica de C ++ 11. ¿Existe una forma limpia de pasar un cierre al método de registro, para que pueda eliminar la condición duplicada "si"? Por ejemplo, estoy buscando un código equivalente al siguiente en la sintaxis anterior a C ++ 11:

void log(int level, std::function<std::string ()> getMessage) {
    if (level <= logLevel) {
        cout << getMessage() << endl;
    }
}

...

int someNum = 3;
log(1, [someNum]() -> std::string {
    std::ostringstream sstream;
    sstream << "Some format " << someNum;
    return sstream.str();
});

La mejor que se me ocurre es:

struct LogMessage {
    virtual std::string operator()() const = 0;
};

void log(int level, const LogMessage &getMessage) {
    if (level <= logLevel) {
        cout << getMessage() << endl;
    }
}

...

struct X : public LogMessage {
    X(int num) : myNum(num) { }
    std::string operator()() const {
        std::ostringstream out;
        out << "Some format " << myNum;
        return out.str();
    }
    private: const int myNum;
} a(someNum);
log(1, a);
2
Jeff G 25 ago. 2016 a las 00:26

2 respuestas

La mejor respuesta

Incluso si las macros comúnmente no se recomiendan, podrían ayudar en este caso específico, especialmente si todo su texto puede ser manejado por secuencias.

Haga que su función de registro sea una macro:

#define LOG(level, msg) { if (level <= logLevel) { cout << msg << endl; } }

Entonces, si lo haces:

LOG( 1, "Some format " << someNum )

La prueba if se realiza y solo uno y cualquier formato complejo realizado en el segundo parámetro de la macro solo se ejecutará si la condición de nivel de registro es true.

Nota: Para las líneas existentes que usan sprintf, aún necesitará declarar una función ...:

inline std::string printNum( int someNum )
{
    char msg[200];
    sprintf(msg, "Some format %d", someNum);
    return msg;
}

LOG( 1, printNum(3) )
2
jpo38 25 ago. 2016 a las 05:50

Para complementar la respuesta proporcionada por @ jpo38, simplemente agregue otra macro para aceptar argumentos variados con el fin de admitir una función de estilo printf:

#define LOGF(LEVEL, ...)\
    if ((LEVEL) <= logLevel) {\
        char msg[200];\
        sprintf(msg, __VA_ARGS__);\
        log((LEVEL), msg);\
    }

Entonces cualquiera de las siguientes llamadas produciría el mismo resultado:

LOG(1, "Some format " << someNum);
LOGF(1, "Some format %d", someNum);
0
Jeff G 31 ene. 2020 a las 18:46