当前位置: 首页 > 知识库问答 >
问题:

如何将给定类型的所有元组元素提取到新元组中

费凯康
2023-03-14

std::get的现有元组重载仅限于按索引或类型返回1个元素。想象一下,一个元组包含多个相同类型的元素,你想把它们都提取到一个新的元组中。

如何实现std::get的版本

template<typename... Ts_out>
constexpr std::tuple<Ts_out...> extract_from_tuple(auto& tuple) {
    // fails in case of multiple occurences of a type in tuple
    return std::tuple<Ts_out...> {std::get<Ts_out>(tuple)...};
}

auto tuple = std::make_tuple(1, 2, 3, 'a', 'b', 'c', 1.2, 2.3, 4.5f);
auto extract = extract_from_tuple <float, double>(tuple);
// expecting extract == std::tuple<float, double, double>{4.5f, 1.2, 2.3}

不确定通过std::get访问每个元素时是否使用std::make_index_sequence


共有3个答案

唐永春
2023-03-14

实现的思路如下(虽然boop. mp11可能只需要几行)。

从元组中提取

#include <array>
#include <tuple>
#include <utility>

template<typename T, class Tuple>
constexpr auto 
extract_tuple_of(const Tuple& t) {
  constexpr auto N = std::tuple_size_v<Tuple>;
  constexpr auto indices = []<std::size_t... Is>
  (std::index_sequence<Is...>) {
    std::array<bool, N> find{
      std::is_same_v<std::tuple_element_t<Is, Tuple>, T>...
    };
    std::array<std::size_t, find.size()> indices{};
    std::size_t size{};
    for (std::size_t i = 0, j = 0; j < find.size(); j++) {
      size += find[j];
      if (find[j])
        indices[i++] = j;
    }
    return std::pair{indices, size};
  }(std::make_index_sequence<N>{});

  return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
    return std::tuple(std::get<indices.first[Is]>(t)...);
  }(std::make_index_sequence<indices.second>{});
};

template<typename... Ts_out, class Tuple>
constexpr auto 
extract_from_tuple(const Tuple& t) {
  return std::tuple_cat(extract_tuple_of<Ts_out>(t)...);
}

演示

constexpr auto tuple = std::make_tuple(1, 2, 3, 'a', 'b', 'c', 1.2, 2.3, 4.5f);
constexpr auto extract1 = extract_from_tuple<float, double>(tuple);
constexpr auto extract2 = extract_from_tuple<int>(tuple);
constexpr auto extract3 = extract_from_tuple<long>(tuple);
static_assert(extract1 == std::tuple<float, double, double>{4.5f, 1.2, 2.3});
static_assert(extract2 == std::tuple<int, int, int>{1, 2, 3});
static_assert(extract3 == std::tuple<>{});
慕承允
2023-03-14
匿名用户

有助推。Mp11:

template <typename... Ts, typename Tuple>
auto extract_from_tuple(Tuple src) {
    // the indices [0, 1, 2, ..., N-1]
    using Indices = mp_iota<mp_size<Tuple>>;
    
    // the predicate I -> Tuple[I]'s type is one of {Ts...}
    using P = mp_bind<
        mp_contains,
        mp_list<Ts...>,
        mp_bind<mp_at, Tuple, _1>>;

    // the indices that satisfy P
    using Chosen = mp_filter_q<P, Indices>;

    // now gather all the appropriate elements
    return [&]<class... I>(mp_list<I...>){
        return std::tuple(std::get<I::value>(src)...);
    }(Chosen{});
}

演示。

如果我们想使用tuple_cat,一个简洁的版本:

template <typename... Ts, typename Tuple>
constexpr auto extract_from_tuple2(Tuple src) {
    auto single_elem = []<class T>(T e){
        if constexpr (mp_contains<mp_list<Ts...>, T>::value) {
            return std::tuple<T>(e);
        } else {
            return std::tuple<>();
        }
    };

    return std::apply([&](auto... e){
        return std::tuple_cat(single_elem(e)...);
    }, src);
}

演示。

何玉韵
2023-03-14

这里只需要C17。

d::tuple_cat是我最喜欢的工具之一。

>

  • 使用std::index_序列仔细检查元组

    使用专门化来拾取std::元组

    使用std::tuple_cat将所有内容粘合在一起。

    唯一棘手的部分是检查是否需要每个元组元素。为此,将所有需要的类型放入它自己的std::tuple,并为该部分使用一个helper类。

    #include <utility>
    #include <tuple>
    #include <iostream>
    
    // Answer one simple question: here's a type, and a tuple. Tell me
    // if the type is one of the tuples types. If so, I want it.
    
    template<typename wanted_type, typename T> struct is_wanted_type;
    
    template<typename wanted_type, typename ...Types>
    struct is_wanted_type<wanted_type, std::tuple<Types...>> {
    
        static constexpr bool wanted=(std::is_same_v<wanted_type, Types>
                          || ...);
    };
    
    // Ok, the ith index in the tuple, here's its std::tuple_element type.
    // And wanted_element_t is a tuple of all types we want to extract.
    //
    // Based on which way the wind blows we'll produce either a std::tuple<>
    // or a std::tuple<tuple_element_t>.
    
    template<size_t i, typename tuple_element_t,
         typename wanted_element_t,
         bool wanted=is_wanted_type<tuple_element_t, wanted_element_t>::wanted>
    struct extract_type {
    
        template<typename tuple_type>
        static auto do_extract_type(const tuple_type &t)
        {
            return std::tuple<>{};
        }
    };
    
    
    template<size_t i, typename tuple_element_t, typename wanted_element_t>
    struct extract_type<i, tuple_element_t, wanted_element_t, true> {
    
        template<typename tuple_type>
        static auto do_extract_type(const tuple_type &t)
        {
            return std::tuple<tuple_element_t>{std::get<i>(t)};
        }
    };
    
    // And now, a simple fold expression to pull out all wanted types
    // and tuple-cat them together.
    
    template<typename wanted_element_t, typename tuple_type, size_t ...i>
    auto get_type_t(const tuple_type &t, std::index_sequence<i...>)
    {
        return std::tuple_cat( extract_type<i,
                       typename std::tuple_element<i, tuple_type>::type,
                       wanted_element_t>::do_extract_type(t)... );
    }
    
    
    template<typename ...wanted_element_t, typename ...types>
    auto get_type(const std::tuple<types...> &t)
    {
        return get_type_t<std::tuple<wanted_element_t...>>(
            t, std::make_index_sequence<sizeof...(types)>());
    }
    
    int main()
    {
        std::tuple<int, const char *, double> t{1, "alpha", 2.5};
    
        std::tuple<double, int> u=get_type<int, double>(t);
    
        std::cout << std::get<0>(u) << " " << std::get<1>(u) << std::endl;
    
        std::tuple<int, int, int, char, char, char, double, double, float> tt;
    
        auto uu=get_type<float, double>(tt);
    
        static_assert(std::is_same_v<decltype(uu),
                  std::tuple<double, double, float>>);
    
        return 0;
    }
    

  •  类似资料:
    • 我在一次采访中被问到以下问题。虽然我用n元树回答了这个问题,但有人告诉我这还不够好。所以,我很好奇,什么是它的最佳解决方案。 输入:整数数组:[2,3,7]和总和:10 输出:加起来等于和的所有数组元素组合(例如2、2、3、3、7等) 谢了小泰

    • 本文向大家介绍从Python中的元组列表中找到包含给定元素的元组,包括了从Python中的元组列表中找到包含给定元素的元组的使用技巧和注意事项,需要的朋友参考一下 列表可以将元组作为其元素。在本文中,我们将学习如何识别包含特定搜索元素(字符串)的元组。 有条件 我们可以根据情况设计跟踪。之后,我们可以提及条件或条件组合。 示例 输出结果 运行上面的代码给我们以下结果- 带过滤器 我们将过滤器功能与

    • 下面我有以下数据。 所以,我不知道为什么UDF可以使用int而不能使用CharArray。此外,我觉得可能有一种方法可以做到这一点,而不使用UDF..但不确定从哪里开始。对这里可能发生的事情有什么建议吗?

    • 问题内容: 我有一个已经有一个类的元素: 现在,我想创建一个JavaScript函数,将一个类添加到(不是替换,而是添加)。 我怎样才能做到这一点? 问题答案: 使用element.classList.add添加一个类: 然后element.classList.remove删除一个类: 如果需要支持Internet Explorer 9或更低版本: 在元素的属性中添加一个空格以及新类的名称。首先,

    • 我有一个类似 我试图使所有元素联合元素,但同一子数组中的元素不得复制。 这将根据第一个子数组中的元素数进行添加。我试过了,但找不到任何解决办法。有人能帮忙吗? 这是我试过的代码: 提前感谢。!

    • 问题内容: 在n = 5和k = 3的情况下,以下循环将执行此操作 但是效率不高,我想使用Banker的序列来完成,因此先探索单例,然后研究配对,然后研究三元组再停止。 我没有找到一种方法,但是至少此循环应该更有效: 还有:但是k个嵌入式循环看起来很丑 问题答案: 即使k个嵌入式循环看起来很丑,这也应该是最有效的方法