2012-09-24 22 views
8

Ho una classe C++ che è il frontend per un sistema di registrazione. La sua funzione di registrazione è implementata utilizzando C++ 11 di modelli variadic:Come utilizzare l'attributo di formato printf di GCC con i modelli variadici C++ 11?

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

Ogni registrazione backend implementa la sua versione di true_log, che, tra le altre cose, utilizza i parametri inoltrati a chiamare vsnprintf. Es .:

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

Tutto funziona alla grande e sono felice.

Ora, voglio aggiungere un controllo statico sui parametri log(): in particolare, vorrei utilizzare l'attributo di formato printf di GCC.

Ho iniziato taggando la funzione log() con __attribute__ ((format (printf, 2, 3))) (come this è il primo parametro "nascosto", ho bisogno di spostare gli indici dei parametri di uno). Questo non funziona, perché se non riesce con un errore di compilazione:

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

Poi, ho provato ad aggiungere lo stesso attributo alla funzione true_log(). Si compila, ma in realtà non viene eseguito alcun controllo degli errori: ho provato a passare a log() alcune combinazioni di formato/variabile non valide e non è stato emesso alcun avviso. Forse questo tipo di controllo è "troppo tardi", o, in altre parole, l'informazione sulla variabile è stata persa nella catena di chiamate?

Come ultima risorsa, se ho annotato log() con __attribute__ ((format (printf, 2, 0))), riceverei avvisi su stringhe di formato errate, ma non verrebbe emessa alcuna diagnostica per combinazioni formato/variabile non valide.

Riassumendo il problema: Come posso controllare il formato completo da GCC se utilizzo i modelli variadic di C++ 11?

+0

Poiché vsnprintf() non può gestire più di quello che può fare la vecchia scuola, perché preoccuparsi con i modelli variadici in primo luogo? –

+1

Perché stai usando modelli variadici quando stai semplicemente buttando via le informazioni sul tipo? Basta rendere 'true_log()' la tua reale funzione di logging. –

+0

Oppure rendere 'Frontend :: log' prendere un argomento variabile ... –

risposta

2

Non credo che tu possa. Scommetto che GCC verifica solo la stringa di formato se è un valore letterale . Questo è il motivo per cui l'attributo format su true_log non funziona: quella funzione viene chiamata con quello che sembra (sintatticamente) come una stringa determinata dal tempo di esecuzione. Inserendo il valore log direttamente si aggirerebbe, ma richiederebbe gli attributi format per supportare il modello variadic, che si è dimostrato non è così.

Suggerisco di guardare più C++ - modi ish per fare output formattato. Esiste, ad esempio, boost::format che funziona in modo simile a printf, ma verifica dinamicamente che il numero e i tipi dei tipi di parametri corrispondano alla stringa di formato. Tuttavia, non utilizza modelli variadici, ma consuma invece i parametri alimentati (tramite operatore%) uno per uno.

1

Per la cronaca, ho finito per rimuovere del tutto i modelli variadici C++ 11 e utilizzando un tradizionale va_list.

__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 
} 
Problemi correlati