代码之家  ›  专栏  ›  技术社区  ›  TypeIA

获取包含元组中除第一个元素外的所有元素的新元组

  •  1
  • TypeIA  · 技术社区  · 7 年前

    给予 std::tuple<A, B, ...> foo std::tuple<B, ...> bar 除了第一个元素 foo

    我用参数包和一些模板元编程编写了一个helper函数来实现这一点,但是我很想扔掉所有这些东西!

    unshift_tuple() 它返回一个元组,其中包含传递给函数的元组的第一个元素以外的所有元素。实施 解压元组() 使用帮助函数 unshift_tuple_with_indices() 它接受一个包含要提取的元组索引的参数包 sequential_integer_list helper类型用于使用模板元编程生成适当的索引列表参数包。丑!

    #include <tuple>
    
    template <size_t... Integers>
    struct integer_list {};
    
    template <size_t N, size_t... Args>
    struct sequential_integer_list : sequential_integer_list<N - 1, N - 1, Args...> {};
    
    template <size_t... Args>
    struct sequential_integer_list<0, Args...> { typedef integer_list<Args...> type; };
    
    template <typename FirstElement, typename... Elements, size_t... Indices>
    static std::tuple<Elements...> unshift_tuple_with_indices(
        const std::tuple<FirstElement, Elements...>& tuple,
        integer_list<Indices...> index_type)
    {
        return std::make_tuple(std::get<Indices + 1>(tuple)...);
    }
    
    template <typename FirstElement, typename... Elements>
    std::tuple<Elements...>
    unshift_tuple(const std::tuple<FirstElement, Elements...>& tuple)
    {
        return unshift_tuple_with_indices(tuple,
            typename sequential_integer_list<sizeof...(Elements)>::type());
    }
    
    int main(int, char *[])
    {
        std::tuple<int, std::string, double> foo(42, "hello", 3.14);
    
        std::tuple<std::string, double> bar = unshift_tuple(foo);
    }
    

    为了清楚起见,这个代码工作得很好。我只想删除它(或它的任何部分),并使用一些内置的东西,如果可能的话!


    Jarod42指出 std::integer_list 在C++ 14中,它简化了实现,例如:

    #include <cstddef>
    #include <tuple>
    #include <utility>
    
    template <typename T1, typename... T, size_t... Indices>
    std::tuple<T...> unshift_tuple_with_indices(
        const std::tuple<T1, T...>& tuple, std::index_sequence<Indices...>)
    {
        return std::make_tuple(std::get<Indices + 1>(tuple)...);
    }
    
    template <typename T1, typename... T> std::tuple<T...>
    unshift_tuple(const std::tuple<T1, T...>& tuple)
    {
        return unshift_tuple_with_indices(tuple,
            std::make_index_sequence<sizeof...(T)>());
    }
    
    2 回复  |  直到 7 年前
        1
  •  2
  •   K. Kiryu    7 年前

    在C++ 14中,有一个名为 std::integer_sequence sequential_integer_list . 你可以在 here .

    template <typename First, typename ... Elements>
    struct unshift_tuple_impl
    {
        using type = std::tuple<Elements...>;
    };
    
    template <typename First, typename ... Elements>
    std::tuple<Elements...>
    unshift_tuple(const std::tuple<First, Elements...>& tuple)
    {
        return typename unshift_tuple_impl<First, Elements...>::type{};
    }
    
        2
  •  1
  •   Jarod42    7 年前

    在C++ 17中,你可以这样做

    template <typename T1, typename... Ts>
    std::tuple<Ts...> unshift_tuple(const std::tuple<T1, Ts...>& tuple)
    {
        return std::apply([](auto&&, const auto&... args) {return std::tie(args...);}, tuple);
    }
    

    std::apply 可以在C++ 14中实现。

    std::index_sequence 避免编写自己的版本,从而将代码简化为:

    namespace details
    {
        template <typename Tuple, size_t... Indices>
        auto unshift_tuple_with_indices(
            const Tuple& tuple,
            std::index_sequence<Indices...> index_type)
        {
            return std::make_tuple(std::get<Indices + 1>(tuple)...);
        }
    }
    
    template <typename T, typename... Ts>
    std::tuple<Ts...> unshift_tuple(const std::tuple<T, Ts...>& tuple)
    {
        return details::unshift_tuple_with_indices(tuple, std::index_sequence_for<Ts...>());
    }
    
    推荐文章