如何在C++中创建类型列表的 n 路笛卡尔积?
How can I create a n way Cartesian product of type lists in C++?
不言自明。
基本上,假设我有这样的类型列表:
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。不幸的是,我不得不坚持使用手卷方法,因为是否使用boost是来自其他地方的决定:(
使用 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>);
https://godbolt.org/z/L5eamT
我把自己的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>);
相关文章:
- 在 OpenGL 中将笛卡尔世界坐标转换为球面局部坐标
- C++ 中unordered_map的有效笛卡尔积
- 谷歌测试:模板模板的笛卡尔乘积的类型列表与模板
- 使用多个输入向量中值的笛卡尔乘积调用 lambda
- 如何在C++中创建类型列表的 n 路笛卡尔积?
- c++17通过生成预先声明的类型列表的笛卡尔乘积来生成std::变体
- 用于将笛卡尔 (x,y,z) 转换为圆柱坐标 (ρ,θ,z) 坐标 2D/3D 的代码
- 将笛卡尔点存储在矢量和输出距离中
- 使用迭代器和可变参数模板的笛卡尔乘积
- 圆的面积 使用笛卡尔平面上的点
- 当元素数> 1000 时,如何制作向量的笛卡尔积?
- 使用提示用户输入笛卡尔平面中某些点的x-y坐标(浮点类型)的函数
- 创建两个可变非类型模板参数包的笛卡尔乘积扩展
- TMP:如何推广向量的笛卡尔积
- 就地生成 2 个向量的笛卡尔积<string>?
- 如何创建类型列表的笛卡尔积
- 如何遍历两个类似stl的容器(笛卡尔积)
- 如何使用笛卡尔积将向量元组转换为元组的向量
- 得到笛卡尔积的算法
- 多字符串的笛卡尔积