代码之家  ›  专栏  ›  技术社区  ›  Tom Huntington

使用std::get进行运行时索引

  •  -1
  • Tom Huntington  · 技术社区  · 1 年前

    我正试着转一个 vector 属于 variant s变成了 tuple 属于 矢量 s variadicly(即,我想将以下代码因素化为一个variadic模板 std::variant<Ts...> ).

    std::vector<std::variant<float, int>> vector_of_variants;
    vector_of_variants.emplace_back(1);
    vector_of_variants.emplace_back(2.f);
    
    std::tuple<std::vector<float>, std::vector<int>> result;
    for (auto& el : vector_of_variants)
    {
        auto index = el.index();
        std::get<index>(result).pushback(std::get<index>(el)); // error: index is runtime value
    }
    

    然而,这条线 std::get<index>(result).pushback(std::get<index>(el)); 显然不起作用,我需要换一些 std::visit 类似行为(即生成线条 tuple_size 时间和运行时的委托)。

    符合人体工程学的方法是什么?


    多亏了user17732522,我成功地使我的模板工作起来 https://godbolt.org/z/Geq1Kvjx9

    1 回复  |  直到 1 年前
        1
  •  2
  •   user17732522    1 年前

    假设您已保证变体和中的相应索引 result 匹配,以下内容应该适用于天真的实现。可能不是最好的性能:

    [&]<std::size_t... Is>(std::index_sequence<Is...>){
        ((index == Is ? std::get<Is>(result).push_back(std::get<Is>(el)) : void()), ...);
    }(std::make_index_sequence<std::tuple_size_v<decltype(result)>>{});
    

    您可能还应该添加一个检查 index == std::variant_npos 以防变体处于无效状态。以上内容将忽略此状态下的变体。


    如果您不关心重复的类型,也可以使用 std::visit 相反:

    std::visit([]<typename V>(V&& v){
        std::get<std::vector<std::remove_cvref_t<V>>>(result).push_back(std::forward<V>(v));
    }, el);
    

    如果变量处于无效状态,这将引发 std::访问 总是这样。它也不支持 const / volatile -适当地限定类型,但这些类型在向量或变体中是不寻常的。

    不幸的是没有 std::访问 传递变量值和类型索引(例如作为 std::integral_constant )给访客。如果需要区分重复的类型,那么在这里会更容易。