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

标签 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>
std::tuple<C,A>
std::tuple<C,B>
std::tuple<C,C>

我的想法是创建一个包含所有这些类型的容器的元组,这样我以后就可以将这些类型中的任何一个存储在容器列表中。

template <typename ...Combinations>
using CombinationList = std::tuple<std::vector<Combinations>...>;

我已经有一种机制可以将一个特定的元素插入到它适合的容器中,但我不知道如何创建组合。

在评论中人们建议使用 std::vector<Combination<std::variant<A,C,B>, std::variant<A,B,C>>> .虽然这在技术上解决了问题,但我不想使用它,因为 A、B C 的大小非常不同,我不想在运行时访问这些变体。此外,在某些时候我需要上传容器中的所有数据

std::tuple<std::vector<Combination>...>

到 GPU,所以我不能在这里使用 std::variant。

我该怎么做?

谢谢!

PD:这与这个问题有关Combination explosion of an enum value (729 combinations...) 在那个问题中,我询问了如何轻松生成容器内的类型。现在我需要生成容器。

最佳答案

I already have a mechanism to inserting a particupar element inside the container in which it fits, but I have no clue on how to create the combinatios.

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

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

它被定义为一个 std::tuple,其中包含具有所有组合的 std::tuple 列表。

所以,举例来说,

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>>

下面是一个完整的编译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, "!" );
 }

关于c++ - 在 C++ 中创建类型列表组合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55005063/

相关文章:

c++ - 别名模板特化问题?

c++ - 如何根据另一个 vector 中的条件从 vector 中删除元素?

c++ - Qt C++ C2143 : syntax error : missing ';' before '*'

c# - 在 WPF 中处理来自 c++ dll 的未处理异常

c++ - 黑客排名极小极大问题,最大和给出错误的负值

c++ - 为什么 operator""隐藏在命名空间中?

c++ - 通过 unix 信号优雅地终止 Qt 应用程序

c++ - 从容器中添加和删除自身

c++ - 这个可变参数模板示例有什么问题?

c++ - 解压可变模板时避免 "recursive"函数调用直到运行时条件