C ++将std :: tuple <a,a,=“”a ... =“”>转换为std :: vector或std :: deque

时间:2017-02-27 20:02:01

标签: c++ tuples c++14

在我写的简单解析器库中,使用std::tuple_cat组合了多个解析器的结果。但是当应用一个多次返回相同结果的解析器时,将这个元组转换为像vector或deque这样的容器变得很重要。

如何做到这一点?如何将std::tuple<A>std::tuple<A, A>std::tuple<A, A, A>等任何元组转换为std::vector<A>

我认为使用typename ...Assizeof ...(As)可能会有这种情况,但我不确定如何创建一个较小的元组来递归调用该函数。或者如何编写迭代解决方案,逐个从元组中提取元素。 (因为std::get<n>(tuple)是在编译时构造的。)

怎么做?

3 个答案:

答案 0 :(得分:14)

随着std::apply()的引入,这非常简单:

include(dirname(__FILE__)). DIRECTORY_SEPARATOR.'project'.DIRECTORY_SEPARATOR.'b.php';

template <class Tuple, class T = std::decay_t<std::tuple_element_t<0, std::decay_t<Tuple>>>> std::vector<T> to_vector(Tuple&& tuple) { return std::apply([](auto&&... elems){ return std::vector<T>{std::forward<decltype(elems)>(elems)...}; }, std::forward<Tuple>(tuple)); } 是一个C ++ 17函数,但可以在C ++ 14中实现(参见可能实现的链接)。作为改进,您可以添加SFINAE或std::apply(),其中元组中的所有类型实际上都是static_assert

正如T.C.指出的那样,这会产生每个元素的额外副本,因为Tstd::initializer_list数组支持。那是不幸的。我们赢得一些不必对每个元素进行边界检查,但在复制上丢失一些。复制最终过于昂贵,另一种实现方式是:

const

有关扩展器技巧的说明,请参阅this answer。请注意,我删除了前导template <class Tuple, class T = std::decay_t<std::tuple_element_t<0, std::decay_t<Tuple>>>> std::vector<T> to_vector(Tuple&& tuple) { return std::apply([](auto&&... elems) { using expander = int[]; std::vector<T> result; result.reserve(sizeof...(elems)); expander{(void( result.push_back(std::forward<decltype(elems)>(elems)) ), 0)...}; return result; }, std::forward<Tuple>(tuple)); } ,因为我们知道包是非空的。使用C ++ 17,使用fold-expression变得更清晰:

0

虽然仍然比 return std::apply([](auto&&... elems) { std::vector<T> result; result.reserve(sizeof...(elems)); (result.push_back(std::forward<decltype(elems)>(elems)), ...); return result; }, std::forward<Tuple>(tuple)); 构造函数更好。不幸的。

答案 1 :(得分:3)

以下是一种方法:

#include <tuple>
#include <algorithm>
#include <vector>
#include <iostream>

template<typename first_type, typename tuple_type, size_t ...index>
auto to_vector_helper(const tuple_type &t, std::index_sequence<index...>)
{
    return std::vector<first_type>{
        std::get<index>(t)...
            };
}

template<typename first_type, typename ...others>
auto to_vector(const std::tuple<first_type, others...> &t)
{
    typedef typename std::remove_reference<decltype(t)>::type tuple_type;

    constexpr auto s =
        std::tuple_size<tuple_type>::value;

    return to_vector_helper<first_type, tuple_type>
        (t, std::make_index_sequence<s>{});
}

int main()
{
    std::tuple<int, int> t{2,3};

    std::vector<int> v=to_vector(t);

    std::cout << v[0] << ' ' << v[1] << ' ' << v.size() << std::endl;
    return 0;
}

答案 2 :(得分:0)

虽然,这并不能完全回答问题,但在某些情况下这仍然可能是合适的。仅当元组中的元素数量在 5、6 左右时。(你知道大小)。

tuple<int, int, int, int> a = make_tuple(1, 2, 3, 4);
auto [p, q, r, s] = a;
vector<int> arr(p, q, r, s); // Now, arr has the same elements as in tuple a

请注意,这是 C++ 17 功能。更多信息here