c++ - ¿Alguien puede explicar el "truco de los índices"?
c++11 tuples (1)
Noté que se mencionaba el "truco de los índices" en el contexto de las tuplas bonitas. Parecía interesante, así que seguí el enlace .
Bueno, eso no fue bien. Entendí la pregunta, pero realmente no podía seguir lo que estaba pasando. ¿Por qué siquiera necesitamos índices de algo? ¿Cómo nos ayudan las diferentes funciones definidas allí? ¿Qué es ''desnudo''? etc.
¿Puede alguien dar una jugada por jugada de eso para los menos expertos en paquetes de parámetros y tuplas variadas?
El problema es: tenemos un std::tuple<T1, T2, ...>
y tenemos alguna función f
que podemos invocar en cada elemento, donde f
devuelve un int
, y queremos almacenar esos resultados en un formación.
Comencemos 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)) );
Excepto que escribir todo lo que se get
es inconveniente y redundante en el mejor de los casos, propenso a errores en el peor. Ahora, supongamos que tenemos un tipo index_sequence<0, 1, 2>
. Podríamos usar eso para colapsar esa inicialización de matriz en una expansión de paquetes 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))... };
}
Eso es porque dentro de la función, f(std::get<Indices>(tuple))...
se expande a f(std::get<0>(tuple)), f(std::get<1>(tuple)), f(std::get<2>(tuple))
. Que es exactamente lo que queremos.
El último detalle del problema es simplemente generar esa secuencia de índice particular. C ++ 14 en realidad nos da una utilidad llamada 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>{}
);
}
mientras que el artículo que vinculó simplemente explica cómo uno podría implementar tal metafunción.
Bare
es probablemente algo así como, de la respuesta de Luc Danton :
template<typename T>
using Bare = typename std::remove_cv<typename std::remove_reference<T>::type>::type;