Pushing and popping the first element of a std::tuple

三世轮回 提交于 2019-12-07 16:02:02

问题


I am writing a function in C++ with a variable number of arguments (and different types) in this way

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;
}

What i would like to do, but I don't know how, is to push and pop elements from the tuple, in particular the first element... something like

//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)

Is this possible?


回答1:


You may do something like

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

Note that it is really basic and doesn't handle tuple of reference, or tuple of const qualified type, but it might be sufficient.




回答2:


Length and types of a std::tuple are determined at compile time. No run-time popping or pushing is possible. You could use a std::vector to provide for the run-time modifications.

The data type for your vector could be a std::variant (C++17) or boost::variant. Both types take a list of supported types at compile time, and can be filled with any value of matching type.

Alternatively, you could use std::any (also C++17) or boost::any to store any type, but with different access semantics.

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



回答3:


With generic lambdas, you can do quite elegant:

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);
}



回答4:


You cannot 'lengthen' the tuple by adding elements - that is not what a tuple represents. The point of a tuple is the binding connection between the different values that make it up, like 'firstname', 'lastname', 'phone'.

What you seem to want is much easier accomplished by using a vector - you can easily add elements to it, and remove them - its size can be arbitrarily changed as needed.



来源:https://stackoverflow.com/questions/39101454/pushing-and-popping-the-first-element-of-a-stdtuple

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!