C++ 在C+中创建类型列表组合+;

C++ 在C+中创建类型列表组合+;,c++,c++14,variadic-templates,template-meta-programming,cartesian-product,C++,C++14,Variadic Templates,Template Meta Programming,Cartesian Product,我正在尝试创建一些工具来创建基于其他类型组合的类型列表 假设我们有三种类型 struct A{}; struct B{}; struct C{}; 我想得到一个元组列表,它有N个类型a、B或C的所有可能组合 对于N=2的情况,这将是 std::tuple<A,A> std::tuple<A,B> std::tuple<A,C> std::tuple<B,A> std::tuple<B,B> std::tuple<B,C>

我正在尝试创建一些工具来创建基于其他类型组合的类型列表

假设我们有三种类型

struct A{};
struct B{};
struct C{};
我想得到一个元组列表,它有N个类型a、B或C的所有可能组合

对于N=2的情况,这将是

std::tuple<A,A>
std::tuple<A,B>
std::tuple<A,C>
std::tuple<B,A>
std::tuple<B,B>
std::tuple<B,C>
std::tuple<C,A>
std::tuple<C,B>
std::tuple<C,C>
std::tuple

在这个问题上,我问我如何能够轻松地生成放入容器中的类型。现在我需要生成容器。

使用在线性存储中存储二维矩阵的类比,所有可能的
A
B
C
对都用一维整数
0,1,…,8
标记,如下所示:

0 -> (0/3, 0%3) = (0,0) -> std::tuple<A,A>
1 -> (1/3, 1%3) = (0,1) -> std::tuple<A,B>
...
8 -> (8/3, 8%3) = (2,2) -> std::tuple<C,C>
0->(0/3,0%3)=(0,0)->std::tuple

模板
结构生成\对\向量
{
静态constexpr std::size\t left\u index=I/std::tuple\u size::value;
静态constexpr std::size\t right\u index=I%std::tuple\u size::value;
使用type=std::vector<
std::tuple::type,
typename std::tuple_元素::type>>;
};
模板
结构进行组合;
模板
结构组合
{
使用tuples=std::tuple;
};
模板
结构组合
{
使用类型=类型名进行组合
::元组;
};
我已经有了在容器中插入particupar元素的机制,但是我不知道如何创建组合

假设您有一个类型列表(例如
a、B、C
)和一个无符号整数
N
,我建议使用

template <std::size_t N, typename ... Ts>
using Combinations = ???
变成

  std::tuple<
      std::tuple<A,A>, std::tuple<A,B>, std::tuple<A,C>,
      std::tuple<B,A>, std::tuple<B,B>, std::tuple<B,C>,
      std::tuple<C,A>, std::tuple<C,B>, std::tuple<C,C>>
std::tuple<
std::tuple,std::tuple,std::tuple,
std::tuple,std::tuple,std::tuple,
std::tuple,std::tuple,std::tuple>
下面是一个完整的编译C++11示例

#include <tuple>
#include <vector>
#include <type_traits>

struct A {};
struct B {};
struct C {};

template <typename T, typename ... Ts>
constexpr std::tuple<T, Ts...> addTupleType (std::tuple<Ts...>);

template <typename T, typename ... Ts>
constexpr auto addType ()
   -> std::tuple<decltype(addTupleType<T>(std::declval<Ts>()))...>;

template <typename ... Ts, typename ... Us>
constexpr auto getCombinations (std::integral_constant<std::size_t, 0u>,
                                std::tuple<Ts...> t, std::tuple<Us ...> u)
   -> decltype( u );

template <std::size_t N, typename ... Ts, typename ... Us,
          typename std::enable_if<(N > 0u), bool>::type = true>
constexpr auto getCombinations (std::integral_constant<std::size_t, N>,
                                std::tuple<Ts...> t, std::tuple<Us ...>)
   -> decltype (getCombinations(
         std::integral_constant<std::size_t, N-1u>{}, t,
         std::tuple_cat(addType<Ts, Us...>()...)));

template <std::size_t N, typename ... Ts>
using Combinations
   = decltype(getCombinations(
         std::integral_constant<std::size_t, N-1u>{},
         std::declval<std::tuple<Ts...>>(),
         std::declval<std::tuple<std::tuple<Ts>...>>()));

template <typename ... Ts>
constexpr auto CombListHelper (std::tuple<Ts...>)
   -> std::tuple<std::vector<Ts>...>;

template <typename T>
using CombinationList = decltype(CombListHelper(std::declval<T>()));


int main()
 {
   using type_1 = Combinations<2u, A, B, C>;
   using type_2 = std::tuple<
      std::tuple<A,A>, std::tuple<A,B>, std::tuple<A,C>,
      std::tuple<B,A>, std::tuple<B,B>, std::tuple<B,C>,
      std::tuple<C,A>, std::tuple<C,B>, std::tuple<C,C>>;

   static_assert( std::is_same<type_1, type_2>::value, "!" );

   using type_3 = CombinationList<Combinations<2u, A, B, C>>;
   using type_4 = std::tuple<
      std::vector<std::tuple<A,A>>, std::vector<std::tuple<A,B>>,
      std::vector<std::tuple<A,C>>, std::vector<std::tuple<B,A>>,
      std::vector<std::tuple<B,B>>, std::vector<std::tuple<B,C>>,
      std::vector<std::tuple<C,A>>, std::vector<std::tuple<C,B>>,
      std::vector<std::tuple<C,C>>>;

   static_assert( std::is_same<type_3, type_4>::value, "!" );
 }
#包括
#包括
#包括
结构A{};
结构B{};
结构C{};
模板
constexpr std::tuple addTupleType(std::tuple);
模板
constexpr自动添加类型()
->std::tuple;
模板
constexpr自动获取组合(标准::积分常数,
std::tuple t,std::tuple u)
->decltype(u);
模板::type=true>
constexpr自动获取组合(标准::积分常数,
std::tuple t,std::tuple)
->decltype(gettype)(
积分常数{},t,
std::tuple_cat(addType()…);
模板
使用组合
=decltype(getcompositions)(
std::积分_常数{},
std::declval(),
std::declval());
模板
constexpr auto-CombListHelper(std::tuple)
->std::tuple;
模板
使用CombinationList=decltype(CombListHelper(std::declval());
int main()
{
使用类型_1=组合;
使用类型_2=std::tuple<
std::tuple,std::tuple,std::tuple,
std::tuple,std::tuple,std::tuple,
std::tuple,std::tuple,std::tuple>;
静态断言(std::is_same::value,“!”;
使用类型_3=组合列表;
使用类型_4=std::tuple<
std::vector,std::vector,
std::vector,std::vector,
std::vector,std::vector,
std::vector,std::vector,
std::vector>;
静态断言(std::is_same::value,“!”;
}

A
std::variant
()的工作量要小得多。您将如何做到这一点?我不知道如何使用一个变量来实现……使用像
std::vector这样的东西怎么样?a、B和C可以有非常不同的大小。这是一个物理模拟器,在引导期间我不关心性能,但在模拟期间我关心(很多)。这就是为什么我不喜欢使用这样的变体。另外,在某个时刻,我会将所有数据上传到GPUYou无法创建包含不同类型对象的向量。C++中没有这样的东西。您的选项是(1)变量向量或(2)指向某些(抽象)基类的(智能)指针向量,而派生类负责具体类型。这是一个很好的尝试,但它仅适用于两个元素的组合(AA、AB、AC、AB),但不适用于三个元素(AAA、ABB、AAB…),无论如何,谢谢,是一个非常好的代码。除法和模选择的类型。。。有趣的想法。@jjcasmar(和max66),很多thx。我希望你一切顺利。顺便说一句,将这种方法推广到三倍或更大的维度可能并不难。@Hiroki是个好主意。我可以编辑一下你对一般情况的回答吗?这是我的建议:@Julius啊,代码不错!但我想保持最新的答案,因为这不是我的代码:)。不用说,你可以把它作为你自己的答案发布。谢谢你,干得好!虽然这并不能完全解决我的问题,但我想我可以以此为出发点。现在我只需要为每个可能的组合生成一个向量。非常感谢@jjcasmar-不确定您到底想要什么,但是。。。答案通过
compositionlist
得到了改进(请参见
main()
中的
type_3
type_4
)哇,令人印象深刻。这正是我想要的。非常感谢
typename std::enable_if 0u),bool>::type=true
似乎不需要。使用
std::integral_constant
重载会更好地匹配。而且,由于只有声明,
constexpr
也不需要。
template <std::size_t N, typename ... Ts>
using Combinations = ???
Combinations<2u, A, B, C>
  std::tuple<
      std::tuple<A,A>, std::tuple<A,B>, std::tuple<A,C>,
      std::tuple<B,A>, std::tuple<B,B>, std::tuple<B,C>,
      std::tuple<C,A>, std::tuple<C,B>, std::tuple<C,C>>
#include <tuple>
#include <vector>
#include <type_traits>

struct A {};
struct B {};
struct C {};

template <typename T, typename ... Ts>
constexpr std::tuple<T, Ts...> addTupleType (std::tuple<Ts...>);

template <typename T, typename ... Ts>
constexpr auto addType ()
   -> std::tuple<decltype(addTupleType<T>(std::declval<Ts>()))...>;

template <typename ... Ts, typename ... Us>
constexpr auto getCombinations (std::integral_constant<std::size_t, 0u>,
                                std::tuple<Ts...> t, std::tuple<Us ...> u)
   -> decltype( u );

template <std::size_t N, typename ... Ts, typename ... Us,
          typename std::enable_if<(N > 0u), bool>::type = true>
constexpr auto getCombinations (std::integral_constant<std::size_t, N>,
                                std::tuple<Ts...> t, std::tuple<Us ...>)
   -> decltype (getCombinations(
         std::integral_constant<std::size_t, N-1u>{}, t,
         std::tuple_cat(addType<Ts, Us...>()...)));

template <std::size_t N, typename ... Ts>
using Combinations
   = decltype(getCombinations(
         std::integral_constant<std::size_t, N-1u>{},
         std::declval<std::tuple<Ts...>>(),
         std::declval<std::tuple<std::tuple<Ts>...>>()));

template <typename ... Ts>
constexpr auto CombListHelper (std::tuple<Ts...>)
   -> std::tuple<std::vector<Ts>...>;

template <typename T>
using CombinationList = decltype(CombListHelper(std::declval<T>()));


int main()
 {
   using type_1 = Combinations<2u, A, B, C>;
   using type_2 = std::tuple<
      std::tuple<A,A>, std::tuple<A,B>, std::tuple<A,C>,
      std::tuple<B,A>, std::tuple<B,B>, std::tuple<B,C>,
      std::tuple<C,A>, std::tuple<C,B>, std::tuple<C,C>>;

   static_assert( std::is_same<type_1, type_2>::value, "!" );

   using type_3 = CombinationList<Combinations<2u, A, B, C>>;
   using type_4 = std::tuple<
      std::vector<std::tuple<A,A>>, std::vector<std::tuple<A,B>>,
      std::vector<std::tuple<A,C>>, std::vector<std::tuple<B,A>>,
      std::vector<std::tuple<B,B>>, std::vector<std::tuple<B,C>>,
      std::vector<std::tuple<C,A>>, std::vector<std::tuple<C,B>>,
      std::vector<std::tuple<C,C>>>;

   static_assert( std::is_same<type_3, type_4>::value, "!" );
 }