简体   繁体   English

std::variant 类型到 std::tuple 的向量

[英]vector of std::variant types to std::tuple

I am working on vector of std::variant types.我正在研究 std::variant 类型的向量。 Is there a way to convert it to std::tuple of the values holded by given std::variants ?有没有办法将它转换为给定 std::variants 持有的值的 std::tuple ?

typedef std::variant<type1, type2,...> a_union;
std::vector<a_union> vec;

For example, I would like to have tuple like:例如,我想有这样的元组:

std::tuple<typeX, typeY, typeX,...>

Where members are types holded by consecutive variants in vector.其中成员是向量中连续变体所持有的类型。

This might be a solution for you, it uses optional and returns nullopt if the vector has incorrect values这可能是您的解决方案,它使用 optional 并在向量具有不正确的值时返回 nullopt

#include <optional>
#include <tuple>
#include <utility>
#include <variant>
#include <vector>
 
template<typename ... T, size_t ... Index>
std::optional<std::tuple<T...>> to_tuple(const std::vector<std::variant<T...>> & vec,
                                         std::index_sequence<Index...>)
{
    if (sizeof ... (T) != vec.size())
        return std::nullopt;
        
    if (not (...&& std::holds_alternative<T>(vec[Index])))
        return std::nullopt;
    return std::tuple<T...>(std::get<T>(vec[Index])...);
}

template<typename ... T>
std::optional<std::tuple<T...>> to_tuple(const std::vector<std::variant<T...>>& vec)
{
    return to_tuple(vec, std::index_sequence_for<T...>{});
}

The comments accurately state that this is probably an XY problem - a tuple requires compile-time information about the types of the data at each index that a vector of variants does not.评论准确地指出,这可能是一个 XY 问题 - 元组需要有关每个索引处的数据类型的编译时信息,而变量向量则不需要。

But, if you're willing to provide that information at the callsite, it's pretty straightforward to use parameter pack expansion to map a list of types to a string of calls to std::get<> .但是,如果您愿意在调用站点提供该信息,则使用参数包扩展将类型列表映射到对std::get<>的调用字符串非常简单。

You can provide that list of types by assuming the order of types in the variant to be the desired variant types at each index, as jo-art 's answer does.您可以通过假设变体中的类型顺序为每个索引处所需的变体类型来提供该类型列表,就像 jo-art 的答案一样。 Here is a way to do by just providing a list of types you expect the tuple the vector to contain, in case they are different:这是一种方法,只需提供您希望向量包含的元组的类型列表,以防它们不同:

template<typename... Ts, typename Container, std::size_t... Is>
auto vector_to_tuple_impl(Container&& items, std::index_sequence<Is...>)
{
    return std::make_tuple(std::get<Ts>(items[Is])...);
}

template <typename... Ts, typename Container>
std::tuple<Ts...> vector_to_tuple(Container&& items)
{
    return vector_to_tuple_impl<Ts...>(items, std::index_sequence_for<Ts...>{});
}

(there's no error handling here, it will throw an std::bad_variant_access if you get the types wrong, and undefined behavior if you extract more elements than exist) (这里没有错误处理,如果类型错误,它将抛出std::bad_variant_access ,如果提取的元素多于存在的元素,则会抛出未定义的行为)

It's the same basic strategy: Use std::index_sequence_for to turn a parameter pack into an expandable parameter pack of container indices (0, 1, 2, etc...).这是相同的基本策略:使用std::index_sequence_for将参数包转换为容器索引(0、1、2 等...)的可扩展参数包。 The integer sequence pack and the type pack are expanded together to get the item at each index, and call std::get to extract the value.整数序列包和类型包一起展开得到每个索引处的项,并调用std::get提取值。

usage:用法:

    using SimpleVariant = std::variant<std::string_view, int>;
    std::vector<SimpleVariant> some_list { "hello", 42, "goodbye" };
    auto as_tuple = vector_to_tuple<std::string_view, int, std::string_view>(some_list);

proof of concept: https://godbolt.org/z/cGEW5s概念证明: https : //godbolt.org/z/cGEW5s

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM