Нажатие и выталкивание первого элемента std::tuple

Я пишу функцию в 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)

Это возможно?

5 ответов

Решение

Вы можете сделать что-то вроде

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

демонстрация

Обратите внимание, что он действительно простой и не обрабатывает кортеж ссылок или кортежей с квалифицированным типом const, но этого может быть достаточно.

С общими лямбдами вы можете сделать довольно элегантно:

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

Длина и типы std::tuple определяются во время компиляции. Нет выталкивания во время выполнения или толкания невозможно. Вы могли бы использовать std::vector обеспечить модификации во время выполнения.

Тип данных для вашего вектора может быть std::variant (C++17) или boost::variant, Оба типа принимают список поддерживаемых типов во время компиляции и могут быть заполнены любым значением соответствующего типа.

В качестве альтернативы, вы можете использовать std::any (также C++ 17) или boost::any хранить любой тип, но с другой семантикой доступа.

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

Вы не можете "удлинить" кортеж, добавив элементы - это не то, что представляет кортеж. Точка кортежа - это связующее соединение между различными значениями, которые составляют его, такими как "имя", "фамилия", "телефон".

То, что вам нужно, гораздо проще сделать с помощью вектора - вы можете легко добавлять к нему элементы и удалять их - его размер можно произвольно изменять по мере необходимости.

Нету. Кортеж не является вектором или изменяемым контейнером. Как только кортеж объявлен, его содержимое является тем, чем оно является.

std::tuple<int, char>

не имеет возможности превратить себя в

std::tuple<int>

удалив его последний элемент. std::tuple<int, char> это совершенно другой тип, чем std::tuple<int>,

Другие вопросы по тегам