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_product
es 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.hpp
lugar 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_assert
pruebas 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
concat
o 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 recursivaconcat
llamada, no afuera. Respuesta (incluidos los casos de prueba) corregida. Prueba que Barry tiene razón con respecto a las expectativas de corrección :)cartesian_product
implementa la recursividad.multiply_all
hace unamultiply_one
lista para cada tipo en elTLs
paquete.cartesian_product::type
es una lista de listas de tipos.multiply_all
toma una lista de tipos y una lista de listas de tipos.multiply_one
toma dos tipos de listasa1, a2, a3
yb1, b2, b3
y 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 quedecltype
es inevitable, simplemente usar el alias que le dio es más intuitivo.