Explicite.
Fondamentalement, disons que j'ai des listes de types comme ceci:
using type_list_1 = type_list<int, somestructA>;
using type_list_2 = type_list<somestructB>;
using type_list_3 = type_list<double, short>;
Ils peuvent être des nombres variés de listes de types.
Comment obtenir une liste de types de produits cartésiens?
result = type_list<
type_list<int, somestructB, double>,
type_list<int, somestructB, short>,
type_list<somestructA, somestructB, double>,
type_list<somestructA, somestructB, short>
>;
J'ai essayé de créer un produit cartésien bidirectionnel comme indiqué ici: Comment créer le produit cartésien d'une liste de types? , mais rien ne semble être si insignifiant.
Pour l'instant j'essaye ...
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{});
}
}
Je dirai simplement que compte tenu de la difficulté de bien faire les choses, utilisez simplement boost comme dans la réponse de Barry. Malheureusement, je dois être bloqué avec une approche roulée à la main car utiliser boost ou non est une décision qui vient d'ailleurs :(
c++
templates
c++17
variadic-templates
themagicalyang
la source
la source
cartesian_product
s'agit d'une liste de listes de types, et à chaque étape de récursivité, vous voulez ajouter des éléments à chaque liste de types interne. Entrer dans ce deuxième niveau d'emballage prend une certaine déduction ...Réponses:
Avec Boost.Mp11 , il s'agit d'un court one-liner (comme toujours):
Démo .
la source
algorithm.hpp
Mp11. Et même dans ce cas, nous parlons de 0,08 s contre 0,12 s. Je dois tenir compte du temps qu'il m'a fallu pour écrire cela aussi.Ok, j'ai compris. Ce n'est pas joli mais ça marche:
https://godbolt.org/z/L5eamT
J'ai laissé mes propres
static_assert
tests là-bas pour ... Eh bien, j'espère qu'ils vous aideront.De plus, je suis sûr qu'il doit y avoir une meilleure solution. Mais c'était le chemin évident "Je sais que cela mènera finalement au but". J'ai finalement dû recourir à l'ajout de a
concat
ou de sortes, je suis sûr qu'il pourrait être utilisé beaucoup plus tôt pour éviter la plupart des cruches.la source
...
doit aller à l'intérieur de l'concat
appel récursif , pas à l'extérieur. Réponse (y compris les cas de test) corrigée. Prouve que Barry a raison concernant les attentes en matière d'exactitude :)cartesian_product
implémente la récursivité.multiply_all
fait unmultiply_one
pour chaque liste de types dans leTLs
pack.cartesian_product::type
est une liste de listes de types.multiply_all
prend une liste de types et une liste de listes de types.multiply_one
prend deux listes de typea1, a2, a3
etb1, b2, b3
et créea1, b1, b2, b3
,a2, b1, b2, b3
,a3, b1, b2, b3
. Vous avez besoin de ces deux niveaux de déduction (multiply_all
,multiply_one
) parce que vous devez descendre deux niveaux de "variadicness", voir mon premier commentaire sur la question.Repliez les expressions à la rescousse
Et tu as fini. Cela présente l'avantage supplémentaire par rapport à la récursivité d'avoir une profondeur d'instanciation O (1).
la source
using result = product_t<t1,t2,t3>
... une façon de le représenter commeusing result = decltype(t1{} * t2{} * t3{});
. Hmm, eh bien maintenant qu'il y pense, puisquedecltype
c'est inévitable, simplement utiliser l'alias que vous avez donné est plus intuitif.