在 C++ 中创建类型列表组合
Create a type list combination of types in 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>
我的想法是创建一个包含所有这些类型的容器的元组,这样我以后可以将任何这些类型存储在容器列表中。
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:这与这个问题有关
在那个问题中,我询问了如何轻松生成容器内的类型。现在我需要生成容器。
类比在线性存储中存储二维矩阵,所有可能的 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>
因此我们可以构造如下的对列表。
这些函数适用于 C++14 及更高版本。
例如,Combinations<A,B,C>::types
等于 std::tuple<std::vector<std::tuple<A,A>>, std::vector<std::tuple<A,B>>, ...>
:
template<std::size_t I, typename Tuple>
struct make_pair_vector
{
static constexpr std::size_t left_index = I/std::tuple_size<Tuple>::value;
static constexpr std::size_t right_index = I%std::tuple_size<Tuple>::value;
using type = std::vector<
std::tuple<typename std::tuple_element< left_index, Tuple>::type,
typename std::tuple_element<right_index, Tuple>::type>>;
};
template <typename T, typename Is>
struct make_combinations;
template <typename Tuple, std::size_t... Is>
struct make_combinations<Tuple, std::index_sequence<Is...>>
{
using tuples = std::tuple<typename make_pair_vector<Is, Tuple>::type...>;
};
template<typename ...Args>
struct Combinations
{
using types = typename make_combinations
<std::tuple<Args...>,
std::make_index_sequence<(sizeof...(Args))*(sizeof...(Args))>>
::tuples;
};
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
,我建议using
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, "!" );
}
我正在尝试创建一些工具来创建基于其他类型组合的类型列表。
假设我们有三种类型
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:这与这个问题有关
类比在线性存储中存储二维矩阵,所有可能的 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>
因此我们可以构造如下的对列表。
这些函数适用于 C++14 及更高版本。
例如,Combinations<A,B,C>::types
等于 std::tuple<std::vector<std::tuple<A,A>>, std::vector<std::tuple<A,B>>, ...>
:
template<std::size_t I, typename Tuple>
struct make_pair_vector
{
static constexpr std::size_t left_index = I/std::tuple_size<Tuple>::value;
static constexpr std::size_t right_index = I%std::tuple_size<Tuple>::value;
using type = std::vector<
std::tuple<typename std::tuple_element< left_index, Tuple>::type,
typename std::tuple_element<right_index, Tuple>::type>>;
};
template <typename T, typename Is>
struct make_combinations;
template <typename Tuple, std::size_t... Is>
struct make_combinations<Tuple, std::index_sequence<Is...>>
{
using tuples = std::tuple<typename make_pair_vector<Is, Tuple>::type...>;
};
template<typename ...Args>
struct Combinations
{
using types = typename make_combinations
<std::tuple<Args...>,
std::make_index_sequence<(sizeof...(Args))*(sizeof...(Args))>>
::tuples;
};
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
,我建议using
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, "!" );
}