2013-03-04 27 views
8

Chciałbym utworzyć funkcję, która pobiera zmienną liczbę argumentów szablonu. Później za pomocą tych argumentów funkcja powinna przejść następującą pozycję:Przekazywanie pozycji argumentu szablonu variadic

template<typename R, typename Args...> 
R myFunction(Data &data, void *function) { 
    auto f = (R (*)(Args...))function; 
    return f(read<Args1>(data, 1), read<Args2>(data, 2), ...);// <-- This is the problem 
} 

Podany kod nie jest oczywiście możliwy do skompilowania. Czy jest jakiś sposób aby to naprawić? Czy istnieje sposób, aby to zrobić bez szablonów variadycznych bez zbytniego powielania kodu?

+2

Jestem pewien, że można uniknąć wskazywania obiektu do rzutowania za pomocą wskaźnika funkcji. – sellibitze

+0

@sellibitze: Czy to jest problem? Ponieważ mogę mieć tylko puste dane użytkownika wskaźnika, które są przekazywane z funkcji C. –

+0

Dane mogą być "void *". To funkcja, która jest "pustką", jest problemem. –

Odpowiedz

14

Tak, to jest możliwe:

// we need a compile-time helper to generate indices 
template< std::size_t... Ns > 
struct indices 
{ 
    typedef indices< Ns..., sizeof...(Ns) > next; 
}; 

template< std::size_t N > 
struct make_indices 
{ 
    typedef typename make_indices< N - 1 >::type::next type; 
}; 

template<> 
struct make_indices<0> 
{ 
    typedef indices<> type; 
}; 

Z tych pomocników, trzeba jedną spedytora dla swojej funkcji tak:

template<typename R, typename... Args, std::size_t... Ns> 
R myFunctionImpl(void *Data, void *function, indices<Ns...>) { 
    auto f = (R (*)(Args...))function; 
    return f(read<Args>(Data, Ns + 1)...);// +1 because indices is zero-based 
} 

template<typename R, typename... Args> 
R myFunction(void *Data, void *function) { 
    return myFunctionImpl< R, Args... >(Data, function, typename make_indices<sizeof...(Args)>::type()); 
} 

EDIT: Jak to działa? Najpierw określamy rozmiar modelu do. make_indices<N>::type następnie rozszerza się do indices<0,1,2,...,N-1>. Jest on podany jako dodatkowy parametr do funkcji implementacji (od forwardera, który właśnie tworzy fałszywą instancję), stąd odjęcie argumentu od strony funkcji implementacji i umieszcza wygenerowane indeksy w pakiecie argumentów Ns.

Funkcja implementacji ma teraz dwa zestawy argumentów o tym samym rozmiarze, a mianowicie Args i Ns. Po rozwinięciu przez ellipsis ..., elipsa rozszerza całe wyrażenie , które jest stosowane do niego i rozszerza wszystkie pakiety parametrów równolegle! W powyższym przykładzie to wyrażenie to read<Args>(Data, Ns+1), które ładnie rozwija się do pseudokodu OP.

+0

Czy możesz wysłać prosty przykład? –

+2

Po prostu to zrobiłem. Czego brakuje w podanym przykładzie? –

+0

To, czego brakuje, jest prawdziwym przykładem. Z 'main()' i niektórymi funkcjami (z 1,2,3 parametrami). W jaki sposób korzystasz z tych funkcji i struktur? –

Powiązane problemy