2012-09-24 14 views
8

Tengo una clase C++ que es la interfaz para un sistema de registro. Su función de registro se implementa el uso de plantillas de C++ variadic 11:¿Cómo usar el atributo de formato printf de GCC con las plantillas variadas de C++ 11?

template <typename... Args> 
void Frontend::log(const char *fmt, Args&&... args) { 
    backend->true_log(fmt, std::forward<Args>(args)...); 
} 

Cada registro backend implementa su propia versión de true_log, que, entre otras cosas, utiliza los parámetros enviados a llamar vsnprintf. Por ejemplo:

void Backend::true_log(const char *fmt, ...) { 
    // other stuff.. 
    va_list ap; 
    va_start(ap, fmt); 
    vsnprintf(buffer, buffer_length, fmt, ap); 
    va_end(ap); 
    // other stuff.. 
} 

Todo funciona muy bien, y estoy contento.

Ahora, quiero agregar una verificación estática en los parámetros log(): específicamente, me gustaría usar el atributo de formato printf de GCC.

Comencé etiquetando la función log() con __attribute__ ((format (printf, 2, 3))) (como this es el primer parámetro "oculto", necesito cambiar los índices de parámetros por uno). Esto no funciona, porque si falla con un error de compilación:

error: args to be formatted is not ‘...’ 

Entonces, traté de añadir el mismo atributo de la función true_log(). Se compila, pero no se realiza ninguna comprobación de errores: Intenté pasar a log() algunas combinaciones inválidas de formato/variable, y no se emitió ninguna advertencia. Tal vez este tipo de control es "demasiado tarde", o, en otras palabras, la información sobre la variable se ha perdido en la cadena de llamadas.

Como último recurso, si anotada log() con __attribute__ ((format (printf, 2, 0))), iba a recibir advertencias sobre las cadenas de formato equivocadas, pero sin diagnóstico serían emitidas por formato combinaciones no válidas/variables.

Resumiendo el problema: cómo puedo tener formato completo la comprobación de GCC si uso las plantillas variadic de C++ 11?

+0

Dado que vsnprintf() no puede hacer frente a más de lo que la vieja escuela ... puede hacer, ¿por qué molestarse con las plantillas variadic en primer lugar? –

+1

¿Por qué está usando plantillas variadic cuando está tirando la información del tipo? Simplemente haga de 'true_log()' su verdadera función de registro. –

+0

O haga que 'Frontend :: log' tome un argumento variable ... –

Respuesta

2

No creo que puedas. Apuesto a que GCC solo verifica la cadena de formato si es literal. Esta es la razón por la cual no funciona el atributo format en true_log, esa función se llama con lo que se ve (sintácticamente) como una cadena determinada por el tiempo de ejecución. Ponerlo en log directamente evitaría eso, pero requeriría los atributos format para soportar la plantilla variadic, que usted demostró que no.

Le sugiero que busque más formas C++ - ish de hacer salida formateada. Hay, por ejemplo, boost::format que funciona algo así como printf, pero verifica dinámicamente que el número y los tipos de los tipos de parámetros coinciden con la cadena de formato. Sin embargo, no usa plantillas variadic, sino que consume los parámetros alimentados (a través del operador%) uno a uno.

1

Para el registro, terminé eliminando por completo las plantillas variadic de C++ 11, y usando un va_list tradicional.

__attribute__((format(printf, 2, 3))) 
void Frontend::log(const char *fmt, ...) { 
    va_list ap; 
    va_start(ap, fmt); 
    backend->true_log(fmt, ap); 
    va_end(ap); 
} 

void Backend::true_log(const char *fmt, va_list ap) { 
    // log the message somehow 
} 
Cuestiones relacionadas