制作cpp排序元组

时间:2017-09-01 17:40:11

标签: c++

这是标准库中std::make_tuple的代码。

template<typename... _Elements>
    inline tuple<typename __decay_and_strip<_Elements>::__type...>
    make_tuple(_Elements&&... __args)
    {
    typedef tuple<typename __decay_and_strip<_Elements>::__type...>
    __result_type;
    return __result_type(std::forward<_Elements>(__args)...);
    }

我想做的是在创建元组之前对__args进行排序,大概是std::sort(..., Compare comp),其中用户传入适当的比较器,可用于对任何类型的事物进行排序。 __args。

但是,我对cpp相对较新,我不理解这个函数中的一半代码,而std::sort需要__args结尾的参数,而且我不确定如何推导出来。

另请注明typename __decay_and_strip<_Elements>::__type..._Elements&&...位......

编辑因为对于任意类型组合,返回类型在编译时将是未知的,通用情况似乎是不可能的。假设所有相同类型,我们用..._Elements替换T,我仍然不确定如何获得&#34; .end()&#34;在__args

中使用的std::sort

1 个答案:

答案 0 :(得分:9)

这可以在中完成,如果元组类型参数是同构的。 (我们不能对非同类型进行排序,因为这需要重新排列类型本身,而且这不是你在编译时可以做的事情。 1

假设同类型,解决方案基本归结为:

  1. 将参数放入数组中。
  2. 对数组进行排序。
  3. 从数组内容中创建一个元组。
  4. 这并不难。首先,我们需要docs来索引我们的数组(对于第3步 - 如果你有C ++ 14,你可以使用indices trick):

    template <std::size_t... Is>
    struct indices {};
    
    template <std::size_t N, std::size_t... Is>
    struct build_indices
      : build_indices<N-1, N-1, Is...> {};
    
    template <std::size_t... Is>
    struct build_indices<0, Is...> : indices<Is...> {};
    

    然后我们需要一种方法从参数包中剥离第一个类型来声明我们的数组(对于步骤1)。作为奖励,我们会检查以确保所有类型都相同:

    template <typename...>
    struct pack_type;
    
    template <typename Head>
    struct pack_type<Head>
    {
        using type = Head;
    };
    
    // Will fail deduction on a non-homogeneous pack.
    template <typename Head, typename... Tail>
    struct pack_type<Head, Head, Tail...> : pack_type<Head, Tail...> {};
    

    最后,我们的分拣器实现带有帮助器来构建索引包:

    template <std::size_t... I, typename Comparer, typename... Ts>
    std::tuple<Ts...> make_sorted_tuple_impl(indices<I...>, Comparer const &c, Ts && ...args)
    {
        typename pack_type<Ts...>::type values[sizeof...(Ts)] = { std::forward<Ts>(args)... };
    
        std::sort(std::begin(values), std::end(values), c);
    
        return std::make_tuple(std::forward<Ts>(values[I])...);
    }
    
    // Special case to handle empty tuples.
    template <typename Comparer>
    std::tuple<> make_sorted_tuple_impl(indices<>, Comparer const &)
    {
        return std::tuple<>();
    }
    
    template <typename Comparer, typename... Ts>
    std::tuple<Ts...> make_sorted_tuple(Comparer const &c, Ts && ...args)
    {
        return make_sorted_tuple_impl(build_indices<sizeof...(Ts)>(), c, std::forward<Ts>(args)...);
    }
    

    std::index_sequence

      

    另请注明typename __decay_and_strip<_Elements>::__type..._Elements&&...位......

    我不打算解释第一个,因为包含__的标识符由C ++实现保留,因此__decay_and_strip是特定于此特定C ++实现的实现细节。

    _Elements&&...是一组右值参考。这允许参数为std::tuple构造函数See it run

    1 我撒了谎。如果值和比较函数是constexpr,你可以这样做,但是把它拉下来的代码将是巨大的,不值得花时间写。