Auto-explicativo.
Basicamente, digamos que eu tenha listas de tipos assim:
using type_list_1 = type_list<int, somestructA>;
using type_list_2 = type_list<somestructB>;
using type_list_3 = type_list<double, short>;
Eles podem ser um número variável de listas de tipos.
Como obtenho uma lista de tipos de produto cartesiano?
result = type_list<
type_list<int, somestructB, double>,
type_list<int, somestructB, short>,
type_list<somestructA, somestructB, double>,
type_list<somestructA, somestructB, short>
>;
Eu falei sobre como criar um produto cartesiano bidirecional, conforme indicado aqui: Como criar o produto cartesiano de uma lista de tipos? , mas n não parece ser tão trivial.
Por enquanto estou tentando ...
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{});
}
}
Vou apenas dizer que, considerando o quão difícil é acertar, use o boost como na resposta de Barry. Infelizmente eu tenho que ficar preso a uma abordagem rolada à mão, porque usar ou não o boost é uma decisão que vem de outro lugar :(
c++
templates
c++17
variadic-templates
themagicalyang
fonte
fonte
cartesian_product
é uma lista de listas de tipos e, a cada etapa da recursão, você deseja anexar itens a cada lista de tipos interna. Entrar nesse segundo nível de embalagem de embalagem leva algum dedução ...Respostas:
Com o Boost.Mp11 , este é um one-liner curto (como sempre):
Demo .
fonte
algorithm.hpp
vez de todo o Mp11. E mesmo assim estamos falando de 0,08s contra 0,12s. Tenho que levar em consideração quanto tempo levei para escrever isso também.OK, entendi. Não é bonito, mas funciona:
https://godbolt.org/z/L5eamT
Deixei meus próprios
static_assert
testes lá por ... Bem, espero que eles ajudem.Além disso, tenho certeza de que deve haver uma solução melhor. Mas esse era o caminho óbvio "Eu sei que isso acabará por levar ao objetivo". Eventualmente, tive que recorrer a adicionar
concat
tipos, tenho certeza de que poderia ser usado muito mais cedo para pular a maior parte do lixo.fonte
...
precisa entrar naconcat
chamada recursiva , não fora. Resposta (incluindo casos de teste) corrigida. Prova Barry direito em relação às expectativas de correção :)cartesian_product
implementa a recursão.multiply_all
faz umamultiply_one
para cada lista de tipos noTLs
pacote.cartesian_product::type
é uma lista de listas de tipos.multiply_all
pega uma lista de tipos e uma lista de listas de tipos.multiply_one
leva duas listas do tipoa1, a2, a3
eb1, b2, b3
e criaa1, b1, b2, b3
,a2, b1, b2, b3
,a3, b1, b2, b3
. Você precisa desses dois níveis de dedução (multiply_all
,multiply_one
) porque precisa descer dois níveis de "variabilidade"; veja meu primeiro comentário sobre a questão.Dobre expressões para o resgate novamente
E você terminou. Isso tem o benefício adicional sobre a recursão de ter profundidade de instanciação O (1).
fonte
using result = product_t<t1,t2,t3>
... alguma maneira de representá-lo comousing result = decltype(t1{} * t2{} * t3{});
. Hmm, bem, agora que ele pensa sobre isso, uma vez quedecltype
é inevitável, simplesmente usar o alias que você deu é mais intuitivo.