2012-06-25 17 views
6

Ultimamente ho lavorato con libffi e, poiché utilizza un'API C, qualsiasi astrazione viene eseguita utilizzando i puntatori void (buon vecchio 'C). Sto creando una classe (con modelli variadic) che utilizza questa API. La dichiarazione della classe è la seguente: (dove Ret = valore di ritorno e Args argomenti = funzione)Modelli Variadic: iterare su tipo/argomento template

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

All'interno di questa classe ho due diverse funzioni dichiarate come pure (semplificato):

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

voglio essere in grado di utilizzare Call da CallbackBind; e questo è il mio problema Non ho idea di come dovrei convertire l'array void* nella lista degli argomenti basata su modelli. Questo è quello che voglio, più o meno:

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

Se questo non è realizzabile, ci sono soluzioni alternative o soluzioni differenti disponibili?

+1

C'è un motivo per cui non è possibile chiamare direttamente nell'API della libreria dal callback? Hai già un 'void *', e già lo prevede. –

+0

Mmm perché dovresti chiamare una funzione modello variadica con una quantità fissa di argomenti? Sulla base del fatto che "la lunghezza di args è uguale a sizeof ... (Args)", allora conosci il numero di argomenti richiesti, perché usare i modelli variadici ?. – mfontanini

+0

@MarkB Poiché 'CallbackBind' è chiamato _from_ API della libreria, sto cercando di chiamare la mia funzione che non usa i puntatori void. @mfontanini Voglio una classe che mima 'std :: function', e quindi ho bisogno di template variadici (come' operator() (Args ...) ') –

risposta

5

Non si desidera eseguire un'iterazione sui tipi, si desidera creare un pacchetto di parametri ed espanderlo in un modello variadic. Hai un array, quindi il pacchetto che vuoi è un pacchetto di interi 0,1,2 ... da servire come indici di array.

#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...>()); 
    } 
}; 

Qualcosa del genere, utilizzando index_tuple.h

Il trucco è che CallbackBind crea un index_tuple di numeri interi che rappresentano le posizioni di ARG, e dispacci ad un'altra funzione che deduce i numeri interi e si espande il pacco in un elenco del cast espressioni da utilizzare come argomenti per la funzione incartata.

+0

Che soluzione elegante! Ha funzionato perfettamente per me. –

Problemi correlati