2015-07-16 20 views
9

Ich bemerkte, dass der "Index-Trick" im Zusammenhang mit hübschen Drucktupeln erwähnt wurde. Es klang interessant, also folgte ich the link.Kann jemand bitte den "Index-Trick" erklären?

Nun, das ist nicht gut gelaufen. Ich verstand die Frage, konnte aber wirklich nicht nachvollziehen, was vor sich ging. Warum brauchen wir überhaupt Indizes? Wie helfen uns die verschiedenen dort definierten Funktionen? Was ist "leer"? etc.

Kann jemand das Ding für die weniger als Experten auf Parameterpaketen und variadic Tupel Stück für Stück geben?

Antwort

12

Das Problem ist: Wir haben eine std::tuple<T1, T2, ...> und wir haben eine Funktion f, die wir für jedes Element nennen können, wo f eine int zurückkehrt, und wir wollen, dass diese Ergebnisse in einem Array speichern.

Beginnen sie mit einem konkreten Fall starten:

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))); 

ausgenommen alle get s auszuschreiben ist unbequem und redundante bestenfalls, fehleranfällig im schlimmsten Fall. Nehmen wir an, wir hatten einen Typ index_sequence<0, 1, 2>. Das könnten wir verwenden das Array Initialisierung in eine variadische Expansion Pack zum Einsturz:

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

das, weil innerhalb der Funktion ist, wird f(std::get<Indices>(tuple))... zu f(std::get<0>(tuple)), f(std::get<1>(tuple)), f(std::get<2>(tuple)) erweitert. Was genau wir wollen.

Das letzte Detail des Problems erzeugt nur diese bestimmte Indexsequenz. C 14 ++ tatsächlich gibt uns eine solche Utility namens 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>{} 
     ); 
} 

während der Artikel, den Sie einfach verknüpft wird erklärt, wie man ein solches metafunction implementieren könnte.

Bare ist wahrscheinlich so etwas wie, von Luc Danton's answer:

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

'Bare' scheint etwas entlang der Linien von' remove_reference_t'. Beachten Sie, dass der Code auf der verknüpften Seite das Tupel durch Weiterleitungsverweis übernimmt, so dass "Tupel" ein Referenztyp sein kann und "tuple_size" bei Referenztypen nicht funktioniert. (Technisch wird das 'remove_cv' nicht benötigt.' Tuple_size' soll mit cv-qualifizierten 'tuple' funktionieren.) –

+1

Große Antwort, wie immer. Ich fand eine mögliche Definition von "Bare" in [dieser Antwort] (http://stackoverflow.com/a/10615119/1274223), die so etwas wie "Decay_t" zu sein scheint. – Alejandro

+0

In der Definition von call_f_detail, meinst du nicht 'f (std :: get (Tupel) ...)' anstatt 'f (std :: get (Tupel)) ...'? – einpoklum

Verwandte Themen