2014-09-04 22 views
6

ich eine Struktur haben, zu speichern, verwendet werden, die ich um meine Anwendung zu übergeben, die eine Reihe von Callback-Funktionen enthält:Kann std :: function eine Funktion mit variadische Argumente

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

I staatliche Kontrolle in der Anwendung handhaben durch Binden verschiedener Funktionen an die verschiedenen Rückrufe, abhängig von dem aktuellen Systemzustand; es funktioniert gut.

Was würde ich jetzt tun möchte, ist ein paar zusätzliche Rückrufe mit Signaturen, die variable Anzahl von Argumenten, ähnlich wie printf hinzufügen: zum Beispiel

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

Diese nicht Arbeit. In Visual C++, erhalte ich eine Fehlermeldung, die besagt:

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

Ich bin immer noch meinen Weg durch diesen Bereich von C++ Syntax Gefühl und würde schätzen es sehr, einen Rat, wie ich von hier aus weitergehen sollte. Mein vorrangiges Ziel ist es, einen Anruf entlang der Linien zu machen, in der Lage sein:

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

... und das Ausgangssignal an eine Konsole gerichtet sein, in eine Datei oder auf ein GUI-Fenster nach dem Systemzustand .

+0

Wenn es sollte ein [ 'std :: ostream' ist verwenden ] (http://www.cplusplus.com/reference/ostream/ostream/ostream/) statt. – nwp

+0

'std :: function' ist nur für Funktionstypen der Form' R (ArgTypes ...) 'definiert, wobei' ArgTypes ...'ist eine Paket-Erweiterung eines Typen-Parameter-Pakets (d. h. eine (möglicherweise leere) Liste von Typen). Also, keine C-Style Variadic Funktionen erlaubt. –

+0

AFAIK keine Spezialisierung von 'std :: function' für variadic Funktionen, siehe eine mögliche Umgehung [hier] (https://www.daniweb.com/software-development/cpp/threads/467086/stdfunction-with-several- or-none-parameters # post2034402), nicht sicher, ob es verwandt ist. – P0W

Antwort

3

bearbeiten: Original Antwort falsch war, geändert aber noch nicht eine gute Antwort sein, sie hier zu Bildungszwecken zu verlassen:

Viele variable Argument Funktionen eine va_list Version. printf zum Beispiel hat vprintf. Diese Varianten verwenden explizit eine va_list anstelle von Ellipsen.

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


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

    return 0; 
} 

Der Aufruf ist jedoch ein Schmerz.

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

Was mit original post falsch war (Dank /u/T.C.): std::function<int(const char*,va_list)> test2(printf) compiliert, die ich was bedeutet, es dauerte "gearbeitet". Es kompiliert jedoch, weil printf Argumente beliebigen Typs (einschließlich einer va_list) akzeptieren kann, und std::function prüft nur, ob es auf diese Weise aufgerufen werden kann.

+0

So funktioniert 'std :: function test2 (printf);' oder sogar 'std :: function test2 (printf) ; '. Es kompiliert, weil '...' mit allem übereinstimmen kann, nicht weil es irgendwie ein Synonym für 'va_list' ist (das ist es ganz sicher nicht). –

+0

@ T.C. Du hast Recht ... Ich kann nicht erklären, warum alles zusammenkommt. Ich bin mir immer noch nicht ganz sicher, was passiert, aber es dauert nicht wirklich eine va_list ... es gibt jedoch eine va_list-Variante von printf, also ändere ich meine Antwort, um das zu reflektieren. Haben Sie eine Erklärung, warum es das akzeptiert? Tatsächlich funktioniert es nach dem Definieren der Eingabetypen ... – IdeaHat

+0

Es funktioniert, weil Sie * printf tatsächlich mit dieser Liste von Argumenten aufrufen und etwas implizit konvertierbares in 'int' zurückholen können (vorausgesetzt natürlich, dass es da ist kein UB durch falsche Formatzeichenfolgen usw.). 'std :: function' interessiert sich nicht wirklich für den Typ der Sache, die es speichert, nur dass es auf die Art und Weise aufgerufen werden kann, die im Template-Parameter angegeben ist. –

0

Im Anschluss an was vorgeschlagen @MadScienceDreams, das ziemlich gut für mich ...

Erstens I definierte Variable-Argument Versionen der std :: Funktionsobjekte in der Struktur verwendet gearbeitet hat, dann die Tatsache, dass diese C++ nicht C einige Methoden als auch hinzuzufügen:

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; 

die Standardimplementierungen der Variable-Argument Funktionen, für den Konsolenausgang, wurden dann (nach erklärt hat ‚unter Verwendung Namensraum std :: Platzhalter;‘ ohne die die Syntax ist nicht zu verwalten):

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

... und ab diesem Punkt kann ich genau die Syntax verwende ich verwenden hatte gehofft, dass: Sie gerade Ausgabe interessiert sind Sie

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