【问题标题】:How to drop element from std::tuple?如何从 std::tuple 中删除元素?
【发布时间】:2020-06-13 20:27:07
【问题描述】:

给定一个

struct A{}; struct B{}; struct C{};
std::tuple<A,B,C> tabc;

如何从中删除第二个元素B 以获取tuple&lt;A,C&gt;,例如

std::tuple<A,C> tac = drop<B>(tabc);

还是一样的

std::tuple<A,C> tac = drop<1>(tabc);

我假设这会产生一个带有元素副本的新类型。

【问题讨论】:

  • 使用std::get 将原始元组中的每个“幸存者”提取到新的元组中。而已;这里没有技巧,只是直接的方法。
  • auto tac = std::make_tuple(std::get&lt;0&gt;(tabc), std::get&lt;2&gt;(tabc));

标签: c++ c++14 stdtuple


【解决方案1】:

查看这个答案如何制作子元组:

Creating a sub-tuple starting from a std::tuple<some_types...>

阅读。通过制作子元组例程,您可以制作drop 的通用版本:

 template<size_t index, typename Tuple>
 auto Drop(const Tuple& t)
 {
     return std::tuple_cat(
         subtuple_v2<0,index>(t), 
         subtuple_v2<index+1, std::tuple_size<Tuple>::value>(t));
 }

其中subtuple_v2&lt;a,b&gt; 是帖子的扩展版本,它从索引ab 生成子元组。

【讨论】:

  • 我要加constexpr
【解决方案2】:

使用元编程技术进行编码非常简单:

template<size_t drop, size_t ...ixs>
constexpr auto calc_drop_sequence_dropper(std::index_sequence<ixs...>)
{
    return std::index_sequence<(ixs >= drop ? ixs + 1 : ixs)...>{};
}

//Creates a monotonically increasing sequence on the range [0, `count`), except
//that `drop` will not appear.
template<size_t count, size_t drop>
constexpr auto calc_drop_copy_sequence()
{
    static_assert(count > 0, "You cannot pass an empty sequence.");
    static_assert(drop < count, "The drop index must be less than the count.");
    constexpr auto count_sequence = std::make_index_sequence<count - 1>();
    return calc_drop_sequence_dropper<drop>(count_sequence);
}

template<typename Tuple, size_t ...ixs>
constexpr auto copy_move_tuple_by_sequence(Tuple &&tpl, std::index_sequence<ixs...>)
{
    using TplType = std::remove_reference_t<Tuple>;

    return std::tuple<std::tuple_element_t<ixs, TplType>...>(
        std::get<ixs>(std::forward<Tuple>(tpl))...);
}

template<size_t drop, typename Tuple>
constexpr auto drop_tuple_element(Tuple &&tpl)
{
    using TplType = std::remove_reference_t<Tuple>;

    constexpr size_t tpl_size = std::tuple_size<TplType>::value;

    constexpr auto copy_seq = calc_drop_copy_sequence<tpl_size, drop>();

    return copy_move_tuple_by_sequence(std::forward<Tuple>(tpl), copy_seq);
}

主要功能是drop_tuple_element,它执行您假设的drop 功能的功能。当然,如果您要删除多个元素,您希望一次性删除它们,而不是单独删除。所以你需要修改代码。

【讨论】:

    【解决方案3】:

    std::tuple 是不可变的,您不能删除或删除。

    std::tuple 是一个固定大小的异构值集合

    根据您的 C++ 品味,使用 std::get(std::tuple)std::make_tuple 创建一个新元组

    auto tac = std::make_tuple(std::get<0>(tabc), std::get<2>(tabc));
    

    或使用 C++14

    auto tac = std::make_tuple(std::get<A>(tabc), std::get<C>(tabc));
    

    【讨论】:

    • 谢谢。但我正在寻找一种更通用的方式。我知道要删除的类型/索引,但不知道其他人。
    【解决方案4】:

    如果您知道元组中对象 A 和 C 的索引,则可以将函数 std::get 与模板参数 size_t 一起使用。否则,您可以使用带有类型模板参数的函数std::get

    这是一个演示程序

    #include <iostream>
    #include <tuple>
    
    struct A
    {
    };
    
    struct B
    {
    };
    
    struct C
    {
    };
    
    int main() 
    {
        auto t1 = std::make_tuple( A(), B(), C() );
        auto t2 = std::make_tuple( std::get<A>( t1 ), std::get<C>( t1 ) );
        auto t3 = std::make_tuple( std::get<0>( t1 ), std::get<2>( t1 ) );
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多