2012-06-25 16 views
6

Pracuję ostatnio z libffi, a ponieważ używa API C, wszelkie abstrakcje są wykonywane za pomocą wskaźników void (good ol 'C). Tworzę klasę (z szablonami variadic), która wykorzystuje ten interfejs API. Deklaracja klasy jest następujący: (gdzie Ret = wartość zwrotna i Args argumenty = function)Wariacyjne szablony: iteracja na argumencie typu/szablonu

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

W tej klasie mam dwie różne funkcje zadeklarowane jako dobrze (uproszczony):

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

chcę aby móc używać Call z CallbackBind; i to jest mój problem. Nie mam pojęcia, w jaki sposób mam przekonwertować tablicę void* na listę szablonów argumentów. To jest to, co chcę bardziej lub mniej:

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

Jeśli nie jest to osiągalne, czy są jakieś obejścia lub różne rozwiązania dostępne?

+1

Czy istnieje powód, dla którego nie można po prostu wywoływać wywołania zwrotnego bezpośrednio w interfejsie API biblioteki? Masz już 'void *' i już tego oczekuje. –

+0

Mmm dlaczego chcesz wywołać funkcję szablonu variadic ze stałą ilością argumentów? W oparciu o fakt, że "długość argumentów jest równa sizeof ... (Args)", to znasz liczbę wymaganych argumentów, po co używać szablonów variadic ?. – mfontanini

+0

@MarkB Ponieważ 'CallbackBind' nazywa się _from_ API biblioteki, staram się wywoływać moją własną funkcję, która nie używa wskaźników void. @mfontanini Chcę klasę, która naśladuje 'std :: function', a więc wymagam szablonów wariatów (takich jak' operator() (Args ...) ') –

Odpowiedz

5

Nie chcesz powtarzać nad typami, chcesz utworzyć pakiet parametrów i rozwinąć go w szablonie variadic. Macie tablicę, więc potrzebna jest paczka liczb całkowitych 0,1,2 ... do pełnienia funkcji wskaźników tablicowych.

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

Coś w tym przy użyciu index_tuple.h

Sztuką jest to, że CallbackBind stwarza obraz index_tuple liczb całkowitych reprezentujących pozycji Arg, a depesze do innej funkcji, która rozpoznaje liczby całkowite i rozszerza pakiet na listę obsady wyrażenia do użycia jako argumenty do funkcji opakowanej.

+0

Co za eleganckie rozwiązanie! Pracowałem bezbłędnie dla mnie. –