2014-09-04 13 views
6

ho una struttura che mi passa intorno al mio programma che contiene una serie di funzioni di callback:Può std :: funzione di essere utilizzata per memorizzare una funzione con argomenti variadic

typedef struct { 
    std::function<void (void)> f1; 
    std::function<void (int)>  f2; 
    std::function<int (float *)> f3; 
    // ... and so on 
} CallbackTable; 

mi occupo di controllo dello Stato all'interno dell'applicazione per associazione di diverse funzioni ai vari callback, a seconda dello stato corrente del sistema; funziona bene

Quello che mi piace ora fare è aggiungere un paio di callback in più con le firme contenenti un numero variabile di argomenti, simile a printf: per esempio,

std::function<int (const char * format, ...)> printToStdOut; 

Questo non lavoro. In Visual C++, ricevo un messaggio di errore indicante:

error C2027: use of undefined type 'std::_Get_function_impl<_Fty>' 

sto ancora sentendo la mia strada attraverso questa zona della sintassi C++ e sarei molto apprezzare qualche consiglio su come devo procedere da qui. Il mio obiettivo primario è quello di essere in grado di effettuare una chiamata lungo le linee di:

myCallbackTable.printToStdOut("I've just eaten %d bananas\r\n", nBananas); 

... e di avere l'output diretto a una console, ad un file o ad una finestra GUI, a seconda dello stato del sistema .

+0

Se è solo uscita siete interessati a è necessario utilizzare un [ 'std :: ostream' ] (http://www.cplusplus.com/reference/ostream/ostream/ostream/). – nwp

+0

'std :: function' è solo definito per i tipi di funzione del modulo' R (ArgTypes ...) ', dove' ArgTypes ...'è un'espansione di pacchetto di un pacchetto di parametri di tipo (ad esempio, una (possibilmente vuota) lista di tipi). Quindi, non sono consentite funzioni variadiche in stile C. –

+0

AFAIK nessuna specializzazione di 'std :: function' per le funzioni variadic, si veda un possibile lavoro in giro [qui] (https://www.daniweb.com/software-development/cpp/threads/467086/stdfunction-with-several- o-nessuno-parametri # post2034402), non sono sicuro se relativo. – P0W

risposta

3

Edit: risposta originale era sbagliata, modificato, ma ancora non può essere una buona risposta, lasciando qui per scopi didattici:

Molte funzioni di argomenti variabili hanno una versione va_list. printf ad esempio ha vprintf. Queste varianti accettano esplicitamente una va_list invece di un'ellissi.

#include <iostream> 
#include <functional> 
#include <cstdarg> 


int main() 
{ 
    std::function<int(const char*,va_list)> test2(vprintf); 

    return 0; 
} 

Invocando esso, tuttavia, è un dolore.

int invoke_variadic(const std::function<int(const char*,va_list)>& ref,const char* a ,...) 
{ 
    va_list args; 
    va_start(args,a); 
    ref(a,args); 
    va_end(args); 
} 

Cosa c'era di sbagliato in post originale (grazie /u/T.C.): std::function<int(const char*,va_list)> test2(printf) compilazioni, che ho preso per il che significa che "ha funzionato". Tuttavia compila perché printf può accettare argomenti di qualsiasi tipo (inclusa una va_list), e std::function controlla solo se può essere invocato in quel modo.

+0

Quindi 'std :: function test2 (printf);', o anche 'std :: function test2 (printf) ; '. Si compila perché '...' può abbinare qualsiasi cosa, non perché sia ​​in qualche modo un sinonimo di 'va_list' (non lo è certamente). –

+0

@ T.C. Hai ragione ... Non so spiegare perché compili tutto. Non sono ancora esattamente sicuro di cosa stia succedendo, ma in realtà non prende una va_list ... comunque c'è una variante va_list di printf, quindi sto cambiando la mia risposta per riflettere questo. Hai qualche spiegazione sul motivo per cui lo accetta? Effettivamente, "funziona" dopo aver definito i tipi di input ... – IdeaHat

+0

Funziona perché tu * puoi * effettivamente invocare 'printf' con quell'elenco di argomenti e recuperare qualcosa implicitamente convertibile in' int' (assumendo ovviamente che ci sia nessun UB causato da stringhe di formato errate ecc.). 'std :: function' in realtà non interessa il tipo di cosa sta memorizzando, solo che può essere invocato nel modo specificato nel parametro template. –

0

A seguito di ciò @MadScienceDreams suggerito, questo ha funzionato piuttosto bene per me ...

In primo luogo, ho definito le versioni variabile argomento della std :: oggetti funzione nel struct, poi utilizzato il fatto che questo è il C++ non C per aggiungere alcuni metodi così:

typedef struct { 
    std::function<void (void)> f1; 
    std::function<void (int)>  f2; 
    std::function<int (float *)> f3; 
    // ... and so on 

    std::function<int (const char * format, va_list args)> vprintToStdOut; 
    std::function<int (const char * format, va_list args)> vprintToStdErr; 

    int printToStdOut(const char * format, ...) 
    { 
     va_list ap; 
     va_start(ap, format); 
     int count = vprintToStdOut(format, ap); 
     va_end(ap); 
     return count; 
    } 

    int printToStdErr(const char * format, ...) 
    { 
     va_list ap; 
     va_start(ap, format); 
     int count = vprintToStdErr(format, ap); 
     va_end(ap); 
     return count; 
    } 

} CallbackTable; 

le implementazioni di default delle funzioni variabile argomento, per l'uscita della console, erano poi (dopo aver dichiarato 'utilizzando namespace std :: segnaposto;' senza la quale la sintassi è ingestibile):

myCallbackTable.vprintToStdOut = std::bind(vfprintf, stdout, _1, _2); 
myCallbackTable.vprintToStdErr = std::bind(vfprintf, stderr, _1, _2); 

... e da questo punto, posso usare esattamente la sintassi speravo di utilizzare:

myCallbackTable.printToStdOut("I like to eat at least %d bananas a day\r\n", nBananas); 
Problemi correlati