【问题标题】:Pushing and popping the first element of a std::tuple推送和弹出 std::tuple 的第一个元素
【发布时间】:2016-12-30 07:10:23
【问题描述】:

我正在用这种方式用 C++ 编写一个具有可变数量的参数(和不同类型)的函数

template<typename ...Ts>
void myFunction(Ts ...args)
{
    //create std::tuple to access and manipulate single elements of the pack
    auto myTuple = std::make_tuple(args...);    

    //do stuff

    return;
}

我想做的,但我不知道怎么做,是从元组中推送和弹出元素,特别是第一个元素......类似

//remove the first element of the tuple thereby decreasing its size by one
myTuple.pop_front()

//add addThis as the first element of the tuple thereby increasing its size by one
myTuple.push_front(addThis)

这可能吗?

【问题讨论】:

  • 可以,但不能作为成员函数。
  • 它的大小是一个编译时属性(模板参数列表的长度)。您不能重复使用相同的类型。
  • @Jarod42 那怎么办?我应该使用哪些功能?
  • 您要在第一个位置插入的新元素(addThis)是相同的还是另一个元素?在第二种情况下,新元素的类型是不同的类型?

标签: c++ c++11 variadic-templates variadic-functions


【解决方案1】:

你可以做类似的事情

template <typename T, typename Tuple>
auto push_front(const T& t, const Tuple& tuple)
{
    return std::tuple_cat(std::make_tuple(t), tuple);
}

template <typename Tuple, std::size_t ... Is>
auto pop_front_impl(const Tuple& tuple, std::index_sequence<Is...>)
{
    return std::make_tuple(std::get<1 + Is>(tuple)...);
}

template <typename Tuple>
auto pop_front(const Tuple& tuple)
{
    return pop_front_impl(tuple,
                          std::make_index_sequence<std::tuple_size<Tuple>::value - 1>());
}

Demo

请注意,它非常基本,不处理引用元组或 const 限定类型的元组,但它可能就足够了。

【讨论】:

  • 我想你在pop_front_impl 中漏掉了一个return
  • 谢谢,但是当我尝试编译(Visual Studio)时,它说:C4430 缺少类型说明符 - 假定为 int。注意:C++ 不支持 default-int
  • 添加了演示链接。您的 MSVC 版本可能不支持自动推导类型:您可以尝试在代码块前添加 -&gt; decltype(std::tuple_cat(std::make_tuple(t), tuple))
  • @BiagioFesta:是的,错别字已修复,并添加了演示链接。
  • @Jarod42 奇怪...我有 2015 社区版。但是,由于您的演示有效,因此对我有利。你帮了我很多,ty。
【解决方案2】:

使用通用 lambda,您可以做得非常优雅:

template<typename Tuple>
constexpr auto pop_front(Tuple tuple) {
    static_assert(std::tuple_size<Tuple>::value > 0, "Cannot pop from an empty tuple");
    return std::apply(
        [](auto, auto... rest) { return std::make_tuple(rest...); }, 
        tuple);
}

【讨论】:

    【解决方案3】:

    std::tuple 的长度和类型在编译时确定。没有运行时弹出或推送是可能的。您可以使用std::vector 来提供运行时修改。

    向量的数据类型可以是std::variant (C++17) 或boost::variant。两种类型都在编译时获取支持的类型列表,并且可以填充任何匹配类型的值。

    或者,您可以使用 std::any(也是 C++17)或 boost::any 来存储 any 类型,但访问语义不同。

    typedef boost::variant<int, std::string, double> value;
    std::vector<value> data;
    data.push_back(value(42));
    data.psuh_back(value(3.14));
    

    【讨论】:

      【解决方案4】:

      你不能通过添加元素来“加长”元组——这不是元组所代表的。元组的要点是组成它的不同值之间的绑定连接,例如“名字”、“姓氏”、“电话”。

      使用矢量可以更轻松地完成您想要的事情 - 您可以轻松地向其中添加元素并删除它们 - 它的大小可以根据需要任意更改。

      【讨论】:

      • 一个向量中的所有元素都必须是相同的类型,这与 OP 元组的成分不同
      • 但是对于向量我不能有不同的变量类型。
      • 你可以制作一个void*的向量,并存储他们的地址。否则,几乎没有什么可做的,unknown 数量的 unknown 不同类型的列表?你期待什么,黑魔法
      • 只要您使用接口,未知数量的未知不同类型的列表可能是std::vector&lt;std::any&gt;
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-22
      • 2019-10-04
      • 1970-01-01
      • 2021-12-14
      • 2019-06-15
      • 2010-11-14
      相关资源
      最近更新 更多