Autoexplicativo.
Básicamente, digamos que tengo listas de tipos así:
using type_list_1 = type_list<int, somestructA>;
using type_list_2 = type_list<somestructB>;
using type_list_3 = type_list<double, short>;
Pueden ser un número variado de listas de tipos.
¿Cómo obtengo una lista de tipos de productos cartesianos?
result = type_list<
type_list<int, somestructB, double>,
type_list<int, somestructB, short>,
type_list<somestructA, somestructB, double>,
type_list<somestructA, somestructB, short>
>;
Aprendí cómo crear un producto cartesiano bidireccional como se indica aquí: ¿Cómo crear el producto cartesiano de una lista de tipos? , pero parece que no es tan trivial.
Por ahora estoy intentando ...
template <typename...> struct type_list{};
// To concatenate
template <typename... Ts, typename... Us>
constexpr auto operator|(type_list<Ts...>, type_list<Us...>) {
return type_list{Ts{}..., Us{}...};
}
template <typename T, typename... Ts, typename... Us>
constexpr auto cross_product_two(type_list<T, Ts...>, type_list<Us...>) {
return (type_list<type_list<T,Us>...>{} | ... | type_list<type_list<Ts, Us>...>{});
}
template <typename T, typename U, typename... Ts>
constexpr auto cross_product_impl() {
if constexpr(sizeof...(Ts) >0) {
return cross_product_impl<decltype(cross_product_two(T{}, U{})), Ts...>();
} else {
return cross_product_two(T{}, U{});
}
}
Solo diré que teniendo en cuenta lo difícil que es hacerlo bien, solo usa boost como en la respuesta de Barry. Desafortunadamente, tengo que estar atascado con un enfoque enrollado a mano porque usar boost o no es una decisión que proviene de otro lugar :(
c++
templates
c++17
variadic-templates
themagicalyang
fuente
fuente

cartesian_productes una lista de listas de tipos, y en cada paso de recursión desea agregar cosas a cada lista de tipos interna. Entrar en ese segundo nivel de empaquetamiento de paquete lleva algún deducción ...Respuestas:
Con Boost.Mp11 , este es un breve resumen (como siempre):
Demostración .
fuente
algorithm.hpplugar de todo Mp11. E incluso entonces estamos hablando 0.08s vs 0.12s. Tengo que tener en cuenta cuánto tiempo me llevó escribir esto también.Ok lo tengo. No es bonito pero funciona:
https://godbolt.org/z/L5eamT
Dejé mis propias
static_assertpruebas allí para ... Bueno, espero que me ayuden.Además, estoy seguro de que tiene que haber una mejor solución. Pero este era el camino obvio "Sé que esto eventualmente conducirá a la meta". Eventualmente tuve que recurrir a agregar una
concato más, estoy seguro de que podría usarse mucho antes para omitir la mayor parte del cruft.fuente
...tiene que ir dentro de la recursivaconcatllamada, no afuera. Respuesta (incluidos los casos de prueba) corregida. Prueba que Barry tiene razón con respecto a las expectativas de corrección :)cartesian_productimplementa la recursividad.multiply_allhace unamultiply_onelista para cada tipo en elTLspaquete.cartesian_product::typees una lista de listas de tipos.multiply_alltoma una lista de tipos y una lista de listas de tipos.multiply_onetoma dos tipos de listasa1, a2, a3yb1, b2, b3y creaa1, b1, b2, b3,a2, b1, b2, b3,a3, b1, b2, b3. Necesita estos dos niveles de deducción (multiply_all,multiply_one) porque necesita descender por dos niveles de "variabilidad", vea mi primer comentario sobre la pregunta.Doblar expresiones al rescate otra vez
Y tu estas listo. Esto tiene el beneficio adicional sobre la recursividad de tener O (1) profundidad de instanciación.
fuente
using result = product_t<t1,t2,t3>... alguna forma de representarlo comousing result = decltype(t1{} * t2{} * t3{});. Hmm, bueno, ahora que lo piensa, ya quedecltypees inevitable, simplemente usar el alias que le dio es más intuitivo.