如何对两个容器元组进行排序?

时间:2016-06-22 15:35:49

标签: c++ c++11

我有两个元组,每个元组包含不同类型的容器。

std::tuple<containerA<typesA>...> tupleA;
std::tuple<containerB<typesB>...> tupleB;

因此,作为示例tupleA可能会像这样定义:

std::tuple<list<int>, list<float>> tupleA;

两个容器containerAcontainerB是不同的类型。 typesAtypesB不相交。我想按大小对元组内的容器进行排序,并能够按类型访问它们。所以,作为一个例子

std::tuple<list<int>, list<float>> tupleA {{2}, {3.3f, 4.2f}};
std::tuple<deque<double>, deque<uint8_t>> tupleB {{2.0, 1.2, 4.4}, {}};

auto sortedArray = sort(tupleA, tupleB);
sortedArray == {deque<uint8_t>, list<int>, list<float>, deque<double>};
sortedArray.get<list<float>>() == {3.3f, 4.2f};
std::get<list<int>>(tupleA).push_back(4);
std::get<list<int>>(tupleA).push_back(5);
std::get<list<int>>(tupleA).push_back(6);
sortedArray = sort(tupleA, tupleB);
sortedArray == {deque<uint8_t>, list<float>, deque<double>, list<int>};

最重要的部分是我必须存储sortedArray并且元组中元素的大小可能会发生变化。我无法创建这样的sort函数。访问sortedArray的实际语法并不重要。

我尝试使用naive索引到sortedArray内的容器数据,例如使用std::pair<A, 1>来引用元组A中的第二个元素,但是我无法访问元组的信息通过它,因为它不是一个constexpr

2 个答案:

答案 0 :(得分:1)

这是可能的但不容易。

首先,您需要生成N个元素的每个排列的编译时列表(它们有N个阶乘)。

写入运行时和编译时置换对象(单独)。

制作从排列到索引的运行时映射。 (地图步骤)

将您的元组转换为(索引,大小)的向量。按大小排序。提取排列。将其映射到排列集的索引。 (排序步骤,使用地图步骤)

编写一个“魔术开关”,它接受一个函数对象f和一个置换索引,并使用编译时置换来调用f。 (神奇的一步)

编写采用编译时置换的代码,并根据它重新排序元组。 (重新排序步骤)

编写带有函数对象ftuple的代码。做(排序步骤)。做(魔术步骤),为它提供第二个函数对象g,它接受​​传入的排列和元组和(重新排序步骤),然后用它调用f

调用执行此操作的函数bob

std::tuple<list<int>, list<float>> tupleA {{2}, {3.3f, 4.2f}};
std::tuple<deque<double>, deque<uint8_t>> tupleB {{2.0, 1.2, 4.4}, {}};

bob(concat_tuple_tie(tupleA, tupleB), [&](auto&& sorted_array){
  assert( std::is_same<
    std::tuple<deque<uint8_t>&, list<int>&, list<float>&, deque<double>&>,
    std::decay_t<decltype(sorted_array)>
  >::value, "wrong order" );
  sortedArray.get<list<float>>() == {3.3f, 4.2f};
});
std::get<list<int>>(tupleA).push_back(4);
std::get<list<int>>(tupleA).push_back(5);
std::get<list<int>>(tupleA).push_back(6);
bob(concat_tuple_tie(tupleA, tupleB), [&](auto&& sorted_array){
  assert( std::is_same<
    std::tuple<deque<uint8_t>&, list<float>&, deque<double>&, list<int>&>,
    std::decay_t<decltype(sorted_array)>
  >::value, "wrong order" );
});

就个人而言,我怀疑你是否需要这样做。

我能做到这一点,但可能需要几个小时,所以我不打算这样做。您可以查看我的magic switch代码,了解上述最神奇的内容。另一个难点是排列步骤。

请注意,代码使用延续传递样式。另请注意, lambda的每个排列都会被实例化,包括错误的排列,因此您的代码必须对每个排列都有效。这可能会导致数量庞大的代码膨胀。

另一种解决方案可能涉及在容器周围创建类型擦除包装器并简单地对它们进行排序,但这不是您要求的。

答案 1 :(得分:1)

描述的问题听起来非常像你想要动态多态,而不是静态多态 - 你解决它的困难是因为你& #39;坚持尝试使用工具表达静态多态性。

即。您需要一个类型(层次结构)用于集合(或指向集合的指针),它允许您在运行时选择集合的类型和数据类型,但仍然为size所需的函数提供统一的接口(例如,通过继承和虚函数)。

e.g。草图的开头可能看起来像

struct SequencePointer
{
    virtual size_t size() const = 0;
    virtual boost::any operator[](size_t n) const = 0;
};

template <typename Sequence>
struct SLSequencePointer
{
    const Sequence *ptr;
    size_t size() const { return ptr->size(); }
    boost::any operator[](size_t n) const { return (*ptr)[n]; }
};