代码之家  ›  专栏  ›  技术社区  ›  Sam Moldenha

如何获取元组c++的前N个元素?

  •  0
  • Sam Moldenha  · 技术社区  · 3 年前

    假设我有一个如下的函数,我如何获得元组的前n个元素?

    template<std::size_t N, class... Ts>
    void foo(Ts... ts){
       std::tuple<Ts...> all_elements(ts...);
       auto first_elements = //the first N elements of the tuple all_elements
    }
    
    

    定义变量的最佳方式是什么 first_elements 与第一个 N 的元素 all_elements 元组?

    使现代化

    这只是Sam Varshavchik对兼容较低版本C++(如C++17)的版本的回答:

    template<typename T, T... ints, class...DTs>
    auto reduce_tuple(std::integer_sequence<T, ints...> int_seq, std::tuple<DTs&&...>&& t){
        return std::forward_as_tuple((std::move(std::get<ints>(t)))...);
    }
    
    template<std::size_t N, class... Ts>
    auto foo(Ts... ts){
       std::tuple<Ts&&...> all_elements(std::forward<Ts>(ts)...);
       return reduce_tuple(std::make_index_sequence<N>{}, std::move(all_elements));  
    }
    
    //usage
    int main(){
        auto t=foo<2>(3, "a", 0.1);
    
        static_assert(std::is_same_v<decltype(t), std::tuple<int, const char*>>);
    
        std::cout << std::get<0>(t) << " " << std::get<1>(t) << "\n";
    }
    
    
    1 回复  |  直到 3 年前
        1
  •  3
  •   Sam Varshavchik    3 年前

    这里有一个经典的C++20解决方案:使用模板闭包,结合 std::integer_sequence

    让我们通过使用通用引用和转发元组来稍微改进一下,以最大限度地减少副本数量。

    以下示例不是定义元组,而是转发第一个 N 参数到另一个函数。

    完全巧合的是,所讨论的函数是 std::make_tuple 那个生成一个元组。但是,任何函数都可以。

    #include <tuple>
    #include <utility>
    #include <iostream>
    #include <type_traits>
    
    template<std::size_t N, typename ...Ts>
    auto foo(Ts && ...ts)
    {
        auto all_elements=std::forward_as_tuple(
            std::forward<Ts>(ts)...
        );
    
        return [&]<std::size_t ...I>(std::index_sequence<I...>)
            {
                return std::make_tuple(std::get<I>(all_elements)...);
            }(
                std::make_index_sequence<N>{}
            );
    }
    
    int main()
    {
        auto t=foo<2>(3, "a", 0.1);
    
        static_assert(std::is_same_v<decltype(t), std::tuple<int, const char*>>);
    
        std::cout << std::get<0>(t) << " " << std::get<1>(t) << "\n";
    }
    

    (live demo)