2016-01-17 15 views
11

I have a variadic zoo che accetta N argomenti, dove N è noto in fase di compilazione (è un parametro template del classe contenente la funzione).Come estrarre un set selezionato di argomenti di una funzione variadic e usarli per chiamare un'altra funzione

template <int N> 
struct B 
{ 
    template <typename... Args> 
    static void zoo(Args... args) 
    { 
     static_assert(size of...(args) == N, ""); 
     // do something 
    } 
}; 

Ho un'altra variadic funzione foo che prende argomenti M, dove M> N ed è noto al momento della compilazione (che è un parametro di modello della classe contenente la funzione). Ho un index_array statico contenente gli indici degli argomenti di pippo Voglio passare allo zoo.

Dal corpo di foo voglio chiamare zoo passando un sottoinsieme selezionato di argomenti di foo.

Qual è il modo migliore per farlo? Idealmente ottenendo un inlining perfetto, vale a dire che tutto è compilato in una sola istruzione senza riferimenti indiretti alle funzioni?

template<int...I> 
struct indices 
{ 
    static constexpr int N = sizeof...(I); 
}; 

template <int M, typename...X> 
struct A 
{ 
    // here I am simplifying, in reality IS will be built at compile time based on X 
    typedef indices<0,2,3> IS; 

    template <typename... Args> 
    static void foo(Args... args) 
    { 
     static_assert(size of...(args) == M, ""); 
     // do some magic to achieve the function call described in pseudo-code 
     // B<IS::N>::zoo(args(IS(0),IS(1),IS(2))) 
     // ideally this should be perfectly inlined to just have the call above 
    } 
}; 

Si prega di notare che il codice sopra è una semplificazione del mio problema, progettato allo scopo di illustrare la domanda.

MODIFICA: Come descritto di seguito, descrivo il caso d'uso: Sto giocando con una libreria basata su modello per pilotare i pin del microcontrollore. Un microcontrollore ha diverse porte (accessibili come byte in memoria) e ciascuna porta ha fino a 8 pin (bit). La classe A è un insieme di pin tramite l'argomento modello X, in cui ogni pin è definito come Pin. La classe B manipola tutti i pin sulla stessa porta. A :: foo è una funzione per modificare alcuni dei pin, con argomenti nello stesso ordine dell'ordine con cui i pin sono specificati nel pacchetto di argomenti del modello X. foo ha bisogno di raggruppare gli argomenti per porte e inviare alle classi B che rappresentano le singole porte, dove tutti gli argomenti sono fusi e scritti sul controller in una singola istruzione.

+0

Potresti descrivere un caso d'uso per questo? Sembra qualcosa che sarebbe orribile fare il debug se dovesse mai rompersi. Se il numero di casi è pari a/coppie zoo è inferiore a circa dieci, vorrei solo codificarli. Magari li trascinano in 'struct A' via CRTP. – Rumburak

+0

Si prega di consultare la descrizione del caso d'uso aggiunta alla domanda. – Fabio

risposta

4

È possibile creare un aiutante per estrarre il nth_arg in questo modo:

template <int I> 
struct ignore 
{ 
    template <typename T> 
    ignore(T&&) // This constructor accepts anything 
    { 
    } 
}; 

template <typename T> 
struct nth_arg; 

template <size_t... DropIndexes> 
struct nth_arg<std::integer_sequence<size_t, DropIndexes...>> 
{ 
    template <typename Arg, typename... Rest> 
    static decltype(auto) get(ignore<DropIndexes>..., // ignore args 0...n-1 
          Arg&& arg, 
          Rest&&...) // also ignore the rest 
    { 
    return std::forward<Arg>(arg); // return nth arg 
    } 
}; 

e quindi chiamare

template <int... Is, typename... Args> 
static void call_zoo(indices<Is...>, Args&&... args) 
{ 
    B<sizeof...(Is)>::zoo(nth_arg<std::make_index_sequence<Is>>::get(
     std::forward<Args>(args)...)...); 
} 

template <int M> 
struct A 
{ 
    typedef indices<0, 2, 3> IS; 

    template <typename... Args> 
    static void foo(Args... args) 
    { 
    static_assert(sizeof...(args) == M, ""); 
    call_zoo(IS{}, std::forward<Args>(args)...); 
    } 
}; 

Se si utilizza C++ 11, è possibile stampare facilmente il proprio integer_sequence.

+0

Soluzione elegante, che non richiede tuple.+1 – Fabio

+1

Vorrei che lo standard includesse una sintassi dello zucchero per accedere all'nth_arg, che mi sembra un caso d'uso comune. – Fabio

+1

Rumburak: solo per farti sapere ho citato la tua risposta [qui] (http://stackoverflow.com/questions/34904049/how-to-create-a-sorted-mapping-integer-index-with-templates) – Fabio

5

Comprimere gli argomenti in una tupla di riferimenti, quindi recuperarli con std::get e un'espansione di pacchetto sugli indici.

template<class Tuple, int... Is> 
static void magic(Tuple&& args, indices<Is...>){ 
    B<IS::N>::zoo(std::get<Is>(std::forward<Tuple>(args))...); 
} 

template <typename... Args> 
static void foo(Args... args) 
{ 
    static_assert(sizeof...(args) == M, ""); 
    magic(std::forward_as_tuple(args...), IS{}); 
} 

(Si consiglia di fare foo prendere i riferimenti di inoltro.)

+0

Questo sembra esattamente quello di cui ho bisogno. Farò un tentativo. Grazie. – Fabio

Problemi correlati