2015-07-16 27 views
9

Ho notato che il "trucco degli indici" viene menzionato nel contesto delle tuple in bella stampa. Sembrava interessante, quindi ho seguito the link.Qualcuno può spiegare il "trucco degli indici"?

Beh, non è andata bene. Ho capito la domanda, ma non potevo davvero seguire quello che stava succedendo. Perché abbiamo persino bisogno di indici di qualcosa? Come ci aiutano le diverse funzioni definite? Cos'è "Bare"? ecc.

Qualcuno può dare un play-by-play di quella cosa ai meno esperti di pacchetti di parametri e tuple variadiche?

risposta

12

Il problema è: abbiamo un std::tuple<T1, T2, ...> e abbiamo qualche funzione f che possiamo chiamare su ogni elemento, dove f restituisce un int, e vogliamo memorizzare i risultati in un array.

Cominciamo con un caso concreto:

template <typename T> int f(T) { return sizeof(T); } 

std::tuple<int, char, double> tup{42, 'x', 3.14}; 
std::array<int, 3> arr{ f(std::get<0>(tup)), 
         f(std::get<1>(tup)), 
         f(std::get<2>(tup))); 

Tranne scrivere tutte quelle get s è scomodo e ridondante nella migliore delle ipotesi, soggetto a errori nel peggiore dei casi. Ora, diciamo che avevamo un tipo index_sequence<0, 1, 2>. Potremmo usarlo per comprimere tale inizializzazione array in un pacchetto di espansione variadic:

template <typename Tuple, size_t... Indices> 
std::array<int, sizeof...(Indices)> 
call_f_detail(Tuple& tuple, index_sequence<Indices...>) { 
    return { f(std::get<Indices>(tuple))... }; 
} 

Questo perché all'interno della funzione, f(std::get<Indices>(tuple))... viene espanso a f(std::get<0>(tuple)), f(std::get<1>(tuple)), f(std::get<2>(tuple)). Che è esattamente quello che vogliamo

L'ultimo dettaglio del problema è solo la generazione di quella particolare sequenza di indici. C++ 14 in realtà ci dà una tale utility chiamata make_index_sequence

template <typename Tuple> 
std::array<int, std::tuple_size<Tuple>::value> 
call_f(Tuple& tuple) { 
    return call_f_detail(tuple, 
     // make the sequence type sequence<0, 1, 2, ..., N-1> 
     std::make_index_sequence<std::tuple_size<Tuple>::value>{} 
     ); 
} 

mentre l'articolo si è collegato semplicemente spiega come si potrebbe implementare tale metafunction.

Bare è probabilmente qualcosa di simile, da Luc Danton's answer:

template<typename T> 
using Bare = typename std::remove_cv<typename std::remove_reference<T>::type>::type; 
+1

'Bare' sembra qualcosa lungo le linee di' remove_reference_t'. Si noti che il codice sulla pagina OP collegata prende la tupla inviando il riferimento, quindi 'Tuple' può essere un tipo di riferimento e' tuple_size' non funziona sui tipi di riferimento. (Tecnicamente, 'remove_cv' non è necessario.' Tuple_size' dovrebbe funzionare correttamente su 'tuple's cv-qualified.) –

+1

Ottima risposta, come al solito. Ho trovato una possibile definizione di 'Bare' in [questa risposta] (http://stackoverflow.com/a/10615119/1274223), che sembra essere qualcosa come' decay_t'. – Alejandro

+0

Nella definizione di call_f_detail, non intendete 'f (std :: get (tupla) ...)' piuttosto che 'f (std :: get (tupla)) ...'? – einpoklum