如何对元组进行任意排序';什么类型? P>一个真正让我恼火的是C++:空的结构> />代码>类< /C> >占用空间。
因此,我认为如何对元组进行任意排序';什么类型? P>一个真正让我恼火的是C++:空的结构> />代码>类< /C> >占用空间。,c++,templates,c++11,template-meta-programming,C++,Templates,C++11,Template Meta Programming,因此,我认为std::tuple(或者一些变体,因为它的(并且编译器的)实现高度依赖于实现)可能能够节省时间,这在某种程度上是可以做到的,但是由于打包和对齐而存在问题。由于编译器将如何对齐结构中的项,因此在非空旁边有一个空的非空旁边有一个空的非空旁边有一个空的非空旁边将大于2个空的非空旁边的2个空 因此,我需要一种基于某些条件对类型重新排序的方法。根据大小对整个列表进行排序是不必要的(在某些情况下可能是有害的),因此我需要一些通用的方法对元组的类型列表进行重新排序,但仍然可以像访问类型列表一样访
std::tuple
(或者一些变体,因为它的(并且编译器的)实现高度依赖于实现)可能能够节省时间,这在某种程度上是可以做到的,但是由于打包和对齐而存在问题。由于编译器将如何对齐结构中的项
,因此在非空旁边有一个空的非空旁边有一个空的非空旁边有一个空的非空旁边将大于2个空的非空旁边的2个空
因此,我需要一种基于某些条件对类型重新排序的方法。根据大小对整个列表进行排序是不必要的(在某些情况下可能是有害的),因此我需要一些通用的方法对元组的类型列表进行重新排序,但仍然可以像访问类型列表一样访问它
我环顾四周,没有发现任何类似的东西,我不知所措。如何做到这一点
例子
struct A{};
结构B{};
//需要根据某些标准重新排序。
std::tuplex;
//在这种情况下,将所有空对象一起移动,如下所示:
//std::tuplex;
//但是仍然需要get(x)返回'int',get(x)返回'B'。
静态断言(std::is_same::value,“0应该是类型A”);
静态断言(std::is_same::value,“1应该是int类型”);
静态断言(std::is_same::value,“2应该是float类型”);
静态断言(std::is_same::value,“3应该是类型B”);
无法手动执行此操作的原因是,这可能是模板的一部分,并且根据参数,元组中的元素可能为空或不为空:
template <typename A, typename B, typename C, typename D>
class X
{
// Need to have this auto arranged given some criteria
// like size or move all of the empties together.
tuple<A, B, C, D> x;
public:
template<int i>
auto get() -> typename std::tuple_element<i, decltype(x)>
{
return get<i>(x);
}
};
// What are these types? Who knows. This could be buried in some
// template library somewhere.
X<T1, T2, T3, T4> x;
模板
X类
{
//需要在给定一些条件的情况下自动安排此项
//如大小或移动所有的空一起。
元组x;
公众:
模板
auto get()->typename std::tuple\u元素
{
返回get(x);
}
};
//这些类型是什么?谁知道呢。这可能埋在某个地方
//模板库。
X;
首先,让我们从基础开始。我们需要一种方法将模板(std::tuple
)转换为元函数类:
template <template <typename...> class Cls>
struct quote {
template <typename... Args>
using apply = Cls<Args...>;
};
过滤器
:
template <typename TL, typename F>
struct filter;
template <typename TL, typename F>
using filter_t = typename filter<TL, F>::type;
template <typename F>
struct filter<typelist<>, F> {
using type = typelist<>;
};
template <typename A, typename... Args, typename F>
struct filter<typelist<A, Args...>, F> {
using type = concat_t<
std::conditional_t<F::template apply<A>::value,
typelist<A>,
typelist<>>,
filter_t<typelist<Args...>, F>
>;
};
template<typename A, typename F>
using filter_one = std::conditional_t<F::template apply<A>::value,
typelist<A>, typelist<>>;
template<typename F, typename... Args>
concat_t<filter_one<Args, F>...> do_filter(typelist<Args...>);
template <typename TL, typename F>
using filter_t = decltype(do_filter<F>(TL()));
给定要放入元组的某些类型的类型列表
,这些类型将变为:
using my_tuple = apply_t<
quote<std::tuple>,
partition_t<
some_typelist,
some_criteria_metafunc_class
>>;
使用我的元组=应用<
引用
分区<
一些类型列表,
一些标准元函数类
>>;
以巴里的所作所为为基础
从这里开始,我需要一个映射元函数来使用原始函数
我该怎么做
首先,提供一些帮助,以方便索引映射。因为我懒惰,我稍微修改了typelist
template <typename... Args>
struct typelist {
static constexpr std::size_t size = sizeof...(Args);
};
template<class T, std::size_t OldIndex, std::size_t NewIndex>
struct index_map_leaf {
using type = T;
static constexpr std::size_t old_index = OldIndex;
static constexpr std::size_t new_index = NewIndex;
};
template<class... Leaves>
struct index_map : Leaves... {};
converted_index_t::new_index
就是新的索引
要构建索引映射,我们分三步来完成。我们首先将类型转换为类型索引对
template<class... Ts, std::size_t... Is>
typelist<index_map_leaf<Ts, Is, 0>...>
do_build_old_indices(typelist<Ts...>, std::index_sequence<Is...>);
template<class TL>
using build_old_indices =
decltype(do_build_old_indices(TL(), std::make_index_sequence<TL::size>()));
考虑到这一点,对index\u map\u leaf
s的typelist
进行分区就是partition\u t
最后,我们转换分区列表,添加新的索引
template<class... Ts, std::size_t... Is, std::size_t...Js>
typelist<index_map_leaf<Ts, Is, Js>...>
do_build_new_indices(typelist<index_map_leaf<Ts, Is, 0>...>,
std::index_sequence<Js...>);
template<class TL>
using build_new_indices =
decltype(do_build_new_indices(TL(), std::make_index_sequence<TL::size>()));
例如,给定
using original_tuple = std::tuple<int, double, long, float, short>;
using f = quote<std::is_integral>;
using partitioner = tuple_partitioner<original_tuple, f>;
你能把这个问题改写成(a)不要太过分的判断和(b)要求一件具体的事情吗?“是否有一种对元组类型列表重新排序的通用方法”的答案是“是”,但如果没有更多关于您实际想要做什么的详细信息,我们就无法提供更详细的答案。类型没有地址。您实际上是在寻找稳定分区的TMP版本。另请参阅。它利用了空基优化。@KerrekSB,你所说的稳定分区的TMP版本是什么意思。我需要一段时间来消化。因此,从这里开始,我需要一个映射元函数来使用原始索引,我该怎么做?@Adrian只是不使用索引。使用类型getter,它们更容易阅读(您知道get(t)
提供的类型,而无需查找t
),仅当类型不同时才有效。这绝不是保证。我可能会用不同的方式编写过滤器
。@T.C.是的,我不喜欢这个,我会想出更好的tmrw。我真的很喜欢decltype(function\u call())
风格。使编写这些元函数变得更加容易,尽管函数的实际名称在返回类型的冗长中丢失了。@Barry,是的,我也发现了这一点。作为template auto-fn(…)->…
,是否更容易理解?不知道这样是否更好。我发现阅读模板元代码非常困难。分区代码是否会将被视为相同的对象按顺序移动?我想这要求太多了吧?@Adrian分区是稳定的。试图创建一个getter函数,但语法不正确:template auto-get(std::tuple&t){return std::get(t);}
其中TP
将是tuple\u分区器
。这应该允许它像get(mytuple)一样使用代码>
template <typename F>
struct not_ {
template <typename Arg>
using apply = std::conditional_t<F::template apply<Args>::value,
std::false_type,
std::true_type>;
};
using my_tuple = apply_t<
quote<std::tuple>,
partition_t<
some_typelist,
some_criteria_metafunc_class
>>;
template <typename... Args>
struct typelist {
static constexpr std::size_t size = sizeof...(Args);
};
template<class T, std::size_t OldIndex, std::size_t NewIndex>
struct index_map_leaf {
using type = T;
static constexpr std::size_t old_index = OldIndex;
static constexpr std::size_t new_index = NewIndex;
};
template<class... Leaves>
struct index_map : Leaves... {};
template<std::size_t OldIndex, std::size_t NewIndex, class T>
index_map_leaf<T, OldIndex, NewIndex>
do_convert_index(index_map_leaf<T, OldIndex, NewIndex>);
template<std::size_t OldIndex, class IndexMap>
using converted_index_t = decltype(do_convert_index<OldIndex>(IndexMap()));
template<class... Ts, std::size_t... Is>
typelist<index_map_leaf<Ts, Is, 0>...>
do_build_old_indices(typelist<Ts...>, std::index_sequence<Is...>);
template<class TL>
using build_old_indices =
decltype(do_build_old_indices(TL(), std::make_index_sequence<TL::size>()));
// Given a metafunction, returns a metafunction that applies the metafunction to
// its arguments' nested typedef type.
template<class F>
struct project_type {
template<class... Args>
using apply = typename F::template apply<typename Args::type...>;
};
template<class... Ts, std::size_t... Is, std::size_t...Js>
typelist<index_map_leaf<Ts, Is, Js>...>
do_build_new_indices(typelist<index_map_leaf<Ts, Is, 0>...>,
std::index_sequence<Js...>);
template<class TL>
using build_new_indices =
decltype(do_build_new_indices(TL(), std::make_index_sequence<TL::size>()));
template<class TL, class F>
using make_index_map =
apply_t<quote<index_map>, build_new_indices<partition_t<build_old_indices<TL>,
project_type<F>>>>;
template<template<class...> class T, class... Args>
typelist<Args...> do_as_typelist(typelist<T<Args...>>);
template<class T>
using as_typelist = decltype(do_as_typelist(typelist<T>()));
template<class Tuple, class F>
struct tuple_partitioner {
using map_type = make_index_map<as_typelist<Tuple>, F>;
using reordered_tuple_type = apply_t<project_type<quote<std::tuple>>,
as_typelist<map_type>>;
template<std::size_t OldIndex>
using new_index_for =
std::integral_constant<std::size_t,
converted_index_t<OldIndex, map_type>::new_index>;
};
using original_tuple = std::tuple<int, double, long, float, short>;
using f = quote<std::is_integral>;
using partitioner = tuple_partitioner<original_tuple, f>;
static_assert(partitioner::new_index_for<0>() == 0, "!");
static_assert(partitioner::new_index_for<1>() == 3, "!");
static_assert(partitioner::new_index_for<2>() == 1, "!");
static_assert(partitioner::new_index_for<3>() == 4, "!");
static_assert(partitioner::new_index_for<4>() == 2, "!");
static_assert(std::is_same<partitioner::reordered_tuple_type,
std::tuple<int, long, short, double, float>>{}, "!");
template<typename A, typename F>
using filter_one = std::conditional_t<F::template apply<A>::value,
typelist<A>, typelist<>>;
template<typename F, typename... Args>
concat_t<filter_one<Args, F>...> do_filter(typelist<Args...>);
template <typename TL, typename F>
using filter_t = decltype(do_filter<F>(TL()));