我需要std::tuple
在运行时通过索引访问 中的值。为此,我编写了一个函数,该函数返回std::variant
具有针对指定索引初始化的相同类型的值。实现涉及递归模板实例化:
template<std::size_t N>
constexpr auto get_n = [](/*tuple-like*/auto&& t, std::size_t index)
{
using variant_type = decltype(std::apply([](auto&&... v){
return std::variant<std::monostate, std::remove_cvref_t<decltype(v)>...>{};
}, t));
constexpr auto size = std::tuple_size_v<std::remove_cvref_t<decltype(t)>>;
if constexpr(N > size)
return variant_type{};
else
{
if(N == index + 1)
return variant_type(std::in_place_index<N>, std::get<N - 1>(t));
else
return get_n<N + 1>(t, index);
}
};
constexpr auto tuple_to_variant(/*tuple-like*/auto&& t, std::size_t index)
{
return get_n<1>(std::forward<decltype(t)>(t), index);
}
我使用的是 c++23 编译器。问题是只有 gcc 编译时没有错误。clang 和 MSVC 编译器进入无限实例化循环。这是编译器中的错误吗?我该如何修复这三个编译器中都编译的代码?
这是 Compiler Explorer演示
由于您正在递归调用 lambda,因此这只能通过 C++23 显式对象参数来实现。这应该有效:
演示
如果你使用
相反。没有理由
get_n
成为 lambda。这是每个编译器都接受的另一种可能的解决方案。优点是 lambda 函数在内部是本地的
tuple_to_variant
,因此它不会在外部作用域中创建任何名称。代码资源管理器演示
具有详细类型的非递归实现将是:
我喜欢把主动/操作/选择论点(
i
)放在第一位,把被动论点(t
)放在最后。