자기 설명.
기본적으로 다음과 같이 유형 목록이 있다고 가정하십시오.
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>
>;
다음과 같이 양방향 카티 전 곱을 만드는 방법에 대해 살펴 보았습니다 . 유형 목록의 카티 전 곱을 만드는 방법은 무엇입니까? 그러나 n 방법은 그리 사소한 것처럼 보이지 않습니다.
지금은 노력하고 있습니다 …
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{});
}
}
나는 그것을 올바르게 얻는 것이 얼마나 어려운지를 고려할 때 Barry의 대답 에서처럼 부스트를 사용하십시오. 불행히도 부스트를 사용하거나 사용하지 않는 것이 다른 곳에서 오는 결정이기 때문에 수동 롤 접근 방식을 고수해야합니다.
답변
Boost.Mp11을 사용하면 이것은 항상 하나의 짧은 라이너입니다.
using result = mp_product<
type_list,
type_list_1, type_list_2, type_list_3>;
데모 .
답변
알았어 예쁘지는 않지만 작동합니다.
template<class ... T>
struct type_list{};
struct somestructA{};
struct somestructB{};
using type_list_1 = type_list<int, somestructA, char>;
using type_list_2 = type_list<somestructB>;
using type_list_3 = type_list<double, short, float>;
template<class TL1, class TL2>
struct add;
template<class ... T1s, class ... T2s>
struct add<type_list<T1s...>, type_list<T2s...>>
{
using type = type_list<T1s..., T2s...>;
};
template<class ... TL>
struct concat;
template<class TL, class ... TLs>
struct concat<TL, TLs...>
{
using type = typename add<TL, typename concat<TLs...>::type>::type;
};
template<class TL>
struct concat<TL>
{
using type = TL;
};
static_assert(std::is_same_v<type_list<int, somestructA, char, double, short, float>, typename add<type_list_1, type_list_3>::type>);
template<class TL1, class TL2>
struct multiply_one;
// Prepends each element of T1 to the list T2.
template<class ... T1s, class ... T2s>
struct multiply_one<type_list<T1s...>, type_list<T2s...>>
{
using type = typename concat<type_list<type_list<T1s, T2s...>...>>::type;
};
static_assert(std::is_same_v<
type_list<
type_list<int, double, short, float>,
type_list<somestructA, double, short, float>,
type_list<char, double, short, float>
>,
typename multiply_one<type_list_1, type_list_3>::type>);
// Prepends each element of TL to all type lists in TLL.
template<class TL, class TLL>
struct multiply_all;
template<class TL, class ... TLs>
struct multiply_all<TL, type_list<TLs...>>
{
using type = typename concat<typename multiply_one<TL, TLs>::type...>::type;
};
static_assert(std::is_same_v<
type_list<
type_list<int, double, short, float>,
type_list<somestructA, double, short, float>,
type_list<char, double, short, float>
>,
typename multiply_all<type_list_1, type_list<type_list_3>>::type>);
static_assert(std::is_same_v<
type_list<
type_list<int, somestructB>,
type_list<somestructA, somestructB>,
type_list<char, somestructB>,
type_list<int, double, short, float>,
type_list<somestructA, double, short, float>,
type_list<char, double, short, float>
>,
typename multiply_all<type_list_1, type_list<type_list_2, type_list_3>>::type>);
template<class TL, class ... TLs>
struct cartesian_product
{
using type = typename multiply_all<TL, typename cartesian_product<TLs...>::type>::type;
};
template<class ... Ts>
struct cartesian_product<type_list<Ts...>>
{
using type = type_list<type_list<Ts>...>;
};
using expected_result = type_list<
type_list<int, somestructB, double>,
type_list<somestructA, somestructB, double>,
type_list<char, somestructB, double>,
type_list<int, somestructB, short>,
type_list<somestructA, somestructB, short>,
type_list<char, somestructB, short>,
type_list<int, somestructB, float>,
type_list<somestructA, somestructB, float>,
type_list<char, somestructB, float>
>;
static_assert(std::is_same_v<expected_result,
cartesian_product<type_list_1, type_list_2, type_list_3>::type>);
나는 static_assert
거기에 내 자신의 테스트를두고 … 음, 그들이 도움이되기를 바랍니다.
또한 더 좋은 해결책이 있어야합니다. 그러나 이것은 “이것이 결국 목표로 이어질 것”이라는 분명한 경로였습니다. 나는 결국에 concat
또는 종류 를 추가하는 것에 의지 해야했다.
답변
다시 구조에 접어 표현
template<typename... Ts>
typelist<typelist<Ts>...> layered(typelist<Ts...>);
template<typename... Ts, typename... Us>
auto operator+(typelist<Ts...>, typelist<Us...>)
-> typelist<Ts..., Us...>;
template<typename T, typename... Us>
auto operator*(typelist<T>, typelist<Us...>)
-> typelist<decltype(T{} + Us{})...>;
template<typename... Ts, typename TL>
auto operator^(typelist<Ts...>, TL tl)
-> decltype(((typelist<Ts>{} * tl) + ...));
template<typename... TLs>
using product_t = decltype((layered(TLs{}) ^ ...));
그리고 당신은 끝났습니다. 이것은 O (1) 인스턴스화 깊이를 갖는 재귀에 비해 추가적인 이점이 있습니다.
struct A0;
struct A1;
struct B0;
struct B1;
struct C0;
struct C1;
struct C2;
using t1 = typelist<A0, A1>;
using t2 = typelist<B0, B1>;
using t3 = typelist<C0, C1, C2>;
using p1 = product_t<t1, t2>;
using p2 = product_t<t1, t2, t3>;
using expect1 = typelist<typelist<A0, B0>,
typelist<A0, B1>,
typelist<A1, B0>,
typelist<A1, B1>>;
using expect2 = typelist<typelist<A0, B0, C0>,
typelist<A0, B0, C1>,
typelist<A0, B0, C2>,
typelist<A0, B1, C0>,
typelist<A0, B1, C1>,
typelist<A0, B1, C2>,
typelist<A1, B0, C0>,
typelist<A1, B0, C1>,
typelist<A1, B0, C2>,
typelist<A1, B1, C0>,
typelist<A1, B1, C1>,
typelist<A1, B1, C2>>;
static_assert(std::is_same_v<p1, expect1>);
static_assert(std::is_same_v<p2, expect2>);