Selbsterklärend.
Angenommen, ich habe Typlisten wie folgt:
using type_list_1 = type_list<int, somestructA>;
using type_list_2 = type_list<somestructB>;
using type_list_3 = type_list<double, short>;
Sie können eine variable Anzahl von Typlisten sein.
Wie erhalte ich eine Typeliste für kartesische Produkte?
result = type_list<
type_list<int, somestructB, double>,
type_list<int, somestructB, short>,
type_list<somestructA, somestructB, double>,
type_list<somestructA, somestructB, short>
>;
Ich habe versucht, ein kartesisches Zwei-Wege-Produkt zu erstellen, wie hier angegeben: Wie erstelle ich das kartesische Produkt einer Typenliste? , aber n Weg scheint nicht so trivial zu sein.
Im Moment versuche ich ...
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{});
}
}
Ich werde nur sagen, wenn man bedenkt, wie schwierig es ist, es richtig zu machen, benutze einfach Boost wie in der Antwort von Barry. Leider muss ich mich an einen handgerollten Ansatz halten, denn Boost zu verwenden oder nicht, ist eine Entscheidung, die von irgendwo anders kommt :(
c++
templates
c++17
variadic-templates
themagicalyang
quelle
quelle
cartesian_product
es sich um eine Liste von Typlisten handelt und dass Sie bei jedem Rekursionsschritt Inhalte an jede innere Typliste anhängen möchten. Der Einstieg in diese zweite Packstufe erfordert einen gewissen Abzug ...Antworten:
Bei Boost.Mp11 ist dies (wie immer) ein kurzer Einzeiler :
Demo .
quelle
algorithm.hpp
anstelle von Mp11 einschließen. Und selbst dann sprechen wir von 0,08 s gegen 0,12 s. Ich muss berücksichtigen, wie lange ich gebraucht habe, um das auch zu schreiben.OK habe es. Es ist nicht schön, aber es funktioniert:
https://godbolt.org/z/L5eamT
Ich habe meine eigenen
static_assert
Tests dort gelassen für ... Nun, ich hoffe, sie helfen.Ich bin mir auch sicher, dass es eine schönere Lösung geben muss. Aber dies war der offensichtliche Weg "Ich weiß, dass dies irgendwann zum Ziel führen wird". Ich musste schließlich auf das Hinzufügen eines
concat
oder mehrerer Sorten zurückgreifen. Ich bin sicher, dass es viel früher verwendet werden könnte, um den größten Teil der Kruft zu überspringen.quelle
...
muss innerhalb des rekursivenconcat
Aufrufs gehen, nicht außerhalb. Antwort (einschließlich Testfälle) korrigiert. Beweist Barry Recht in Bezug auf Korrektheitserwartungen :)cartesian_product
implementiert die Rekursion.multiply_all
führtmultiply_one
für jede Typliste imTLs
Paket eine aus.cartesian_product::type
ist eine Liste von Typlisten.multiply_all
Nimmt eine Typliste und eine Liste von Typlisten.multiply_one
nimmt zwei Typenlistena1, a2, a3
undb1, b2, b3
und schaffta1, b1, b2, b3
,a2, b1, b2, b3
,a3, b1, b2, b3
. Sie benötigen diese beiden Abzugsebenen (multiply_all
,multiply_one
), da Sie zwei Ebenen der "Variadizität" herabsteigen müssen, siehe meinen ersten Kommentar zu der Frage.Falten Sie die Ausdrücke zur Rettung erneut
Und du bist fertig. Dies hat den zusätzlichen Vorteil gegenüber der Rekursion, dass die Instanziierungstiefe O (1) beträgt.
quelle
using result = product_t<t1,t2,t3>
... eine Art, es als darzustellenusing result = decltype(t1{} * t2{} * t3{});
. Hmm, nun, da es darüber nachdenkt, dadecltype
es unvermeidlich ist, ist es intuitiver, einfach den von Ihnen angegebenen Alias zu verwenden.