Самоочевидно.
В основном, скажем, у меня есть списки типов, например, так:
using type_list_1 = type_list<int, somestructA>;
using type_list_2 = type_list<somestructB>;
using type_list_3 = type_list<double, short>;
Они могут быть различными числами списков типов.
Как я могу получить список картезианского продукта?
result = type_list<
type_list<int, somestructB, double>,
type_list<int, somestructB, short>,
type_list<somestructA, somestructB, double>,
type_list<somestructA, somestructB, short>
>;
Я попробовал создать двустороннее декартово произведение, как показано здесь: Как создать декартово произведение списка типов? , но русский путь, кажется, не так тривиально.
Сейчас я пытаюсь ...
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{});
}
}
Я просто скажу, что, учитывая, насколько сложно это сделать правильно, просто используйте повышение, как в ответе Барри. К сожалению, я должен быть застрял с ручным подходом, потому что использовать повышение или нет - решение, которое приходит откуда-то еще :(
c++
templates
c++17
variadic-templates
themagicalyang
источник
источник
cartesian_product
это список списков типов, и на каждом шаге рекурсии вы хотите добавлять материал в каждый внутренний список типов. Попадание в этот второй уровень упаковки требует некоторого вычета ...Ответы:
С Boost.Mp11 это короткий однострочный (как всегда):
Demo .
источник
algorithm.hpp
все Mp11. И даже тогда мы говорим 0,08 с 0,12 с. Нужно учитывать, сколько времени мне понадобилось, чтобы написать это тоже.Хорошо понял. Это не красиво, но это работает:
https://godbolt.org/z/L5eamT
Я оставил там свои собственные
static_assert
тесты для ... Ну, я надеюсь, они помогут.Кроме того, я уверен, что должно быть лучшее решение. Но это был очевидный путь «я знаю, что это в конечном итоге приведет к цели». В конце концов мне пришлось прибегнуть к добавлению
concat
или сортировки, я уверен, что это можно было использовать намного раньше, чтобы пропустить большую часть промахов.источник
...
Должен идти внутри рекурсивногоconcat
вызова, а не снаружи. Ответ (включая контрольные примеры) исправлен. Доказывает, что Барри прав в отношении правильности ожиданий :)cartesian_product
реализует рекурсию.multiply_all
делаетmultiply_one
для каждого списка типов вTLs
пакете.cartesian_product::type
список списков типовmultiply_all
принимает список типов и список списков типов.multiply_one
принимает два списка типаa1, a2, a3
иb1, b2, b3
и создаетa1, b1, b2, b3
,a2, b1, b2, b3
,a3, b1, b2, b3
. Вам нужны эти два уровня дедукции (multiply_all
,multiply_one
), потому что вам нужно спуститься вниз на два уровня «вариативности», см. Мой первый комментарий к вопросу.Сложите выражения снова на помощь
И вы сделали. Это имеет дополнительное преимущество по сравнению с рекурсией, имея O (1) глубину реализации.
источник
using result = product_t<t1,t2,t3>
... какой-то способ представить это какusing result = decltype(t1{} * t2{} * t3{});
. Хм, хорошо, теперь, когда он думает об этом, посколькуdecltype
это неизбежно, просто использование псевдонима, как вы дали, является более интуитивным.