gpt4 book ai didi

c++ - 如何任意排序元组的类型?

转载 作者:太空狗 更新时间:2023-10-29 23:50:19 26 4
gpt4 key购买 nike

关于 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");

这不能手动完成的原因是这可能是模板的一部分,元组中的元素可能为空或不为空,具体取决于参数:

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 所做的为基础。

So from here I'd need a mapping meta-function to use the original indices, how would I do that?

首先,一些帮助索引映射的助手。又因为懒,修改了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>()));

接下来,我们对这些对进行划分。我们需要一个将另一个元函数应用于其参数的嵌套 typedef 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...>;
};

鉴于此,对 typelist 进行分区的 index_map_leaf s 就是 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>>{}, "!");

Demo .


附言这是我的 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()));

关于c++ - 如何任意排序元组的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32169249/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com