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

How can I get the first N elements of a tuple c++?

提问人:Sam Moldenha 提问时间:9/2/2023 最后编辑:Sam Moldenha 更新时间:9/2/2023 访问量:122

问:

假设我有一个如下函数,我怎么能得到一个元组的前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_elementsNall_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";
}

C++ 元组 stdtuple variadic-tuple-tuple-types

评论

0赞 Sam Varshavchik 9/2/2023
骑兵由 C++20 组成,这是一个专门用于 的模板闭包,并使用 ...std::index_sequencestd::make_index_sequence
0赞 Vivick 9/2/2023
查看 stackoverflow.com/questions/40112646/...
0赞 Jan Schultke 9/2/2023
@SamVarshavchik您实际上需要一个函数,还是只需要调用另一个具有第一个参数的函数?std::tupleNfoo
0赞 Sam Varshavchik 9/2/2023
问题似乎是:这是一个元组,让我更短,@JanSchultke。
0赞 Jan Schultke 9/2/2023
@SamVarshavchik我不太确定。这有点取决于如何使用。很有可能它实际上并不需要是一个元组,并且该元组会立即被输入到另一个函数中,例如 .first_elementsstd::apply

答:

3赞 Sam Varshavchik 9/2/2023 #1

下面是一个经典的 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";
}

(现场演示)