Wyjaśniające.
Zasadniczo powiedz, że mam takie listy typów:
using type_list_1 = type_list<int, somestructA>;
using type_list_2 = type_list<somestructB>;
using type_list_3 = type_list<double, short>;
Mogą to być różne listy typów.
Jak uzyskać listę typową produktu kartezjańskiego?
result = type_list<
type_list<int, somestructB, double>,
type_list<int, somestructB, short>,
type_list<somestructA, somestructB, double>,
type_list<somestructA, somestructB, short>
>;
Zastanawiałem się, jak stworzyć dwukierunkowy produkt kartezjański, jak podano tutaj: Jak stworzyć produkt kartezjański z listy typów? , ale żaden sposób nie wydaje się taki trywialny.
Na razie próbuję ...
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{});
}
}
Powiem tylko, że biorąc pod uwagę, jak trudno jest to zrobić poprawnie, po prostu użyj wzmocnienia, jak w odpowiedzi Barry'ego. Niestety muszę utknąć w podejściu ręcznie toczonym, ponieważ użycie boosta lub nie jest decyzją, która pochodzi z innego miejsca :(
c++
templates
c++17
variadic-templates
themagicalyang
źródło
źródło
cartesian_product
jest to lista list typów, a na każdym kroku rekursji chcesz dołączyć elementy do każdej wewnętrznej listy typów. Wejście na drugi poziom pakowania paczki wymaga pewnej dedukcji ...Odpowiedzi:
W przypadku Boost.Mp11 jest to krótki linijka (jak zawsze):
Demo .
źródło
algorithm.hpp
zamiast Mp11. I nawet wtedy mówimy o 0,08s vs 0,12s. Muszę wziąć pod uwagę, ile czasu zajęło mi napisanie tego.Ok, rozumiem. To nie jest ładne, ale działa:
https://godbolt.org/z/L5eamT
Zostawiłem tam własne
static_assert
testy dla ... Mam nadzieję, że pomogą.Jestem też pewien, że musi być lepsze rozwiązanie. Ale to była oczywista ścieżka „wiem, że ostatecznie doprowadzi to do celu”. W końcu musiałem skorzystać z dodania a
concat
lub sorts, jestem pewien, że można go użyć znacznie wcześniej, aby pominąć większość cruft.źródło
...
Musi przejść wewnątrz rekurencyjnegoconcat
wywołania, a nie na zewnątrz. Odpowiedź (w tym przypadki testowe) poprawiona. Udowadnia, że Barry ma rację co do oczekiwań dotyczących poprawności :)cartesian_product
implementuje rekurencję.multiply_all
robimultiply_one
dla każdej listy typów wTLs
paczce.cartesian_product::type
to lista list typów.multiply_all
pobiera listę typów i listę list typów.multiply_one
zajmuje dwie listy typua1, a2, a3
ab1, b2, b3
i tworzya1, b1, b2, b3
,a2, b1, b2, b3
,a3, b1, b2, b3
. Potrzebujesz tych dwóch poziomów dedukcji (multiply_all
,multiply_one
), ponieważ musisz zejść o dwa poziomy „różnorodności”, patrz mój pierwszy komentarz do pytania.Ponownie złóż wyrażenia na ratunek
I jesteś skończony. Ma to dodatkową zaletę w stosunku do rekurencji o głębokość tworzenia instancji O (1).
źródło
using result = product_t<t1,t2,t3>
... w jakiś sposób przedstawić to jakousing result = decltype(t1{} * t2{} * t3{});
. Hmm, cóż, teraz, gdy się nad tym zastanowić, ponieważdecltype
jest to nieuniknione, po prostu użycie podanego aliasu jest bardziej intuicyjne.