2012-06-25 12 views
6

Ich habe in letzter Zeit mit libffi gearbeitet, und da es eine C-API verwendet, wird jede Abstraktion durch Verwendung von void-Zeigern (good ol 'C) durchgeführt. Ich erstelle eine Klasse (mit variadischen Vorlagen), die diese API verwendet. Die Klassendeklaration ist die folgende: (wobei Ret = Rückgabewert und Args = Funktionsargumente)Variadic Vorlagen: Iterieren über Typ/Vorlage Argument

template <typename Ret, typename... Args> 
class Function 

Innerhalb dieser Klasse Ich habe zwei verschiedene Funktionen als auch erklärt (vereinfacht):

Ret Call(Args... args); // Calls the wrapped function 
void CallbackBind(Ret * ret, void * args[]); // The libffi callback function (it's actually static...) 

Ich möchte in der Lage sein, Call von CallbackBind zu verwenden; und das ist mein Problem. Ich habe keine Ahnung, wie ich das Array void* in die Templates-Liste konvertieren soll. Dies ist, was ich will mehr oder weniger:

CallbackBind(Ret * ret, void * args[]) 
{ 
// I want to somehow expand the array of void pointers and convert each 
// one of them to the corresponding template type/argument. The length 
// of the 'void*' vector equals sizeof...(Args) (variadic template argument count) 

// Cast each of one of the pointers to their original type 
*ret = Call(*((typeof(Args[0])*) args[0]), *((typeof(Args[1])*) args[1]), ... /* and so on */); 
} 

Ist dies nicht erreichbar ist, gibt es Workarounds oder verschiedene Lösungen zur Verfügung?

+1

Gibt es einen Grund, warum Sie nicht einfach aus dem Rückruf direkt in die API der Bibliothek aufrufen können? Sie haben bereits ein 'void *', und das erwartet es bereits. –

+0

Mmm warum möchten Sie eine Variadic Template-Funktion mit einer festen Anzahl von Argumenten aufrufen? Basierend auf der Tatsache, dass "die Länge von Argumenten gleich der Größe von ... (Arg)" ist, kennen Sie die Anzahl der erforderlichen Argumente, warum variadische Vorlagen verwenden ?. – mfontanini

+0

@MarkB Da 'CallbackBind' von der API der Bibliothek aufgerufen wird, versuche ich meine eigene Funktion aufzurufen, die keine void-Zeiger verwendet. @mfontanini Ich möchte eine Klasse, die 'std :: function' nachahmt, und daher brauche ich variadic Vorlagen (wie' operator() (Args ...) ') –

Antwort

5

Sie möchten nicht über die Typen iterieren, sondern ein Parameterpaket erstellen und es in einer variadischen Vorlage erweitern. Sie haben ein Array, also ist das Paket, das Sie wollen, ein Paket mit ganzen Zahlen 0,1,2 ..., die als Array-Indizes dienen.

#include <redi/index_tuple.h> 

template<typename Ret, typename... Args> 
struct Function 
{ 
    Ret (*wrapped_function)(Args...); 

    template<unsigned... I> 
    Ret dispatch(void* args[], redi::index_tuple<I...>) 
    { 
    return wrapped_function(*static_cast<Args*>(args[I])...); 
    } 

    void CallbackBind(Ret * ret, void * args[]) 
    { 
    *ret = dispatch(args, to_index_tuple<Args...>()); 
    } 
}; 

So etwas ist index_tuple.h

Der Trick dass CallbackBind ein index_tuple von ganzen Zahlen darstellt, die ARG-Positionen, und Versendungen auf eine andere Funktion, die die ganzen Zahlen und erweitert die Packung in eine Liste von gegossenen folgert schafft Ausdrücke, die als Argumente für die umbrochene Funktion verwendet werden sollen.

+0

Was für eine elegante Lösung! Arbeitete einwandfrei für mich. –

Verwandte Themen