如何任意对元组的类型进行排序?
How can I arbitrarily sort a tuple's types?
c++最让我恼火的一件事是空的struct
/class
占用空间。
所以,我有这样的想法,std::tuple
(或一些变体,因为它(和编译器的)实现是高度依赖于实现的)可能能够挽救这一天,它有点这样做,但由于包装和对齐存在问题。由于编译器将如何对齐struct
中的项,因此在非空旁边放置一个空,在非空旁边放置一个空,将大于在2个非空旁边放置2个空。
因此,我需要一种基于某些标准对类型重新排序的方法。根据大小对整个列表进行排序是不必要的(在某些情况下可能是有害的),所以我需要一些通用的方法来重新排序元组的类型列表,但仍然像原始顺序一样访问它。
我四处找了一下,没有找到这样的东西,我很困惑。如何做到这一点?
<标题> 例子struct A{};
struct B{};
// Need to be reordered based on some criteria.
std::tuple<A, int, B, float> x;
// In this case move all of the empty objects together like:
// std::tuple<A, B, int, float> x;
// but still have get<1>(x) return the `int` and get<2>(x) return `B`.
static_assert(std::is_same<decltype(get<0>()), A>::value, "0 should be type A");
static_assert(std::is_same<decltype(get<1>()), int>::value, "1 should be type int");
static_assert(std::is_same<decltype(get<2>()), B>::value, "2 should be type float");
static_assert(std::is_same<decltype(get<3>()), float>::value, "3 should be type B");
不能手工完成的原因是它可能是模板的一部分,并且tuple中的元素可能为空或不为空,这取决于参数:
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;
标题>
以Barry的做法为基础。
所以从这里我需要一个映射元函数来使用原始的指标,我怎么做呢?
首先是一些帮助器,以方便索引映射。因为我很懒,我稍微修改了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... {};
给定一个正确构建的index_map
,从旧索引到新索引的转换很简单,利用模板参数推导和重载解析:
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()));
converted_index_t<OldIndex, IndexMap>::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>()));
接下来,我们划分对。我们需要一个元函数将另一个元函数应用于其参数的嵌套类型pedef type
,而不是应用于参数本身。
// 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...>;
};
鉴于此,将index_map_leaf
s的typelist
划分为partition_t<LeafList, project_type<F>>
。
最后,我们对分区列表进行变换,添加新的索引。
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>()));
通过直接从index_map
构造重排序元组类型,可以只进行一次分区。
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>>{}, "!");
演示。
注:以下是我的filter
版本:
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()));
首先,让我们从基础开始。我们需要一种将模板模板(std::tuple
)转换为元函数类的方法:
template <template <typename...> class Cls>
struct quote {
template <typename... Args>
using apply = Cls<Args...>;
};
和类型列表:
template <typename... Args>
struct typelist { };
和一些东西在它们之间:
template <typename F, typename TL>
struct apply;
template <typename F, typename... Args>
struct apply<F, typelist<Args...>> {
using type = typename F::template apply<Args...>;
};
template <typename F, typename TL>
using apply_t = typename apply<F, TL>::type;
所以给定一个类型列表,我们可以有:
using my_tuple = apply_t<quote<std::tuple>, some_typelist>;
现在,我们只需要一个分区符:
template <typename TL, typename F>
struct partition {
using type = concat_t<filter_t<TL, F>,
filter_t<TL, not_t<F>>
>;
};
Where concat
:
template <typename... Args>
struct concat;
template <typename... Args>
using concat_t = typename concat<Args...>::type;
template <typename... A1, typename... A2, typename... Args>
struct concat<typelist<A1...>, typelist<A2...>, Args...> {
using type = concat_t<typelist<A1..., A2...>, Args...>;
};
template <typename TL>
struct concat<TL> {
using type = TL;
};
filter
:
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>
>;
};
And not_
:
template <typename F>
struct not_ {
template <typename Arg>
using apply = std::conditional_t<F::template apply<Args>::value,
std::false_type,
std::true_type>;
};
给定some_typelist
的类型,你想把它放在你的tuple
变成:
using my_tuple = apply_t<
quote<std::tuple>,
partition_t<
some_typelist,
some_criteria_metafunc_class
>>;
- 对任何类型的元素数组进行排序
- 带有枚举方向/类型的气泡排序结构数组
- 标准::map键类型的严格弱排序概念
- 无法使用接口类型对priority_queue中的对象进行排序<T>
- 是否使用cv::Point2f类型重载std::排序
- 按类型排序向量并按类型或派生类型搜索
- C++ MDC final-在字符类型的数组结构中按字母顺序对记录中的名称进行排序
- 我对C 中共享指针列表进行排序的功能未完成类型
- C 使用单个函数对具有多种值类型的数组排序
- 排序时引用绑定到 'value_type' 类型的 null 指针
- 如何对对象数组进行排序,而不考虑对象变量类型
- 为什么我的气泡排序不适用于双精度数据类型?
- 按相互包含对类型进行排序
- 具有双重类型的C++快速排序问题
- C++列表::排序<未解析的重载函数类型>
- 对标准库容器类型进行排序的static_assert() 的优雅方式
- 排序测试模板化函数 lambda:非法使用此类型作为表达式
- std::使用本地类型Compare进行排序
- 是否可以在运行时定义要在STXXL中排序的类型的长度
- 尝试输入整数行并在以矢量作为存储的函数的插入排序类型中排序