获取一个std :: tuple元素作为std :: variant [英] Get a std::tuple element as std::variant

查看:94
本文介绍了获取一个std :: tuple元素作为std :: variant的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出一个变量类型:

using Variant = std::variant<bool, char, int, float, double, std::string>;

和一个元组类型,其中包含仅限于此变体类型的元素(可以重复和省略,但不能附加类型):

and a tuple type containing elements restricted to this variant types (duplicates and omissions are possible, but no additional types):

using Tuple = std::tuple<char, int, int, double, std::string>;

如何在运行时实现通过给定索引获取和设置元组元素为Variant的方法:

How to implement methods that gets and sets a tuple element by a given index as Variant at runtime:

Variant Get(const Tuple & val, size_t index);
void Set(Tuple & val, size_t index, const Variant & elem_v);

我的代码中有两个实现,但我有一个更好的印象。我的第一个实现使用 std :: function ,第二个实现构建一些 Accessor 指针的数组,这些指针对移动和复制我的对象(因为其地址更改)。我想知道是否有人知道实现此目标的正确方法。

I have two implementations in my code, but I have an impression that there can be a better one. My first implementation uses std::function and the second builds an array of some Accessor pointers that imposes restrictions on moving and copying my object (because its address changes). I wonder if someone knows the right way to implement this.

EDIT1:

以下示例可能澄清了我的意思:

The following example probably clarifies what I mean:

Tuple t = std::make_tuple(1, 2, 3, 5.0 "abc");
Variant v = Get(t, 1);
assert(std::get<int>(v) == 2);
Set(t, 5, Variant("xyz"));
assert(std::get<5>(t) == std::string("xyz"));


推荐答案

我将继续我的主题,推荐Boost .mp11适用于所有元编程内容,因为始终有一个功能。在这种情况下,我们需要 mp_with_index 。该函数将运行时索引提升为编译时索引。

I'm going to continue my theme of recommending Boost.Mp11 for all metaprogramming things, because there is always a function for that. In this case, we want mp_with_index. That function lifts a runtime index into a compile-time index.

Variant Get(Tuple const& val, size_t index)
{
    return mp_with_index<std::tuple_size_v<Tuple>>(
        index,
        [&](auto I){ return Variant(std::get<I>(val)); }
        );
}

鉴于在OP中,元组和变量的索引不为了甚至排队, Set 需要实际访问 Variant ,而不是依赖索引。我在这里使用 is_assignable 作为约束,但是可以对其进行调整以适合该问题(例如,可能应该为 is_same )。

Given that in the OP, the indices of the Tuple and the Variant don't even line up, the Set needs to actually visit the Variant rather than relying on the index. I'm using is_assignable here as the constraint, but that can be adjusted to as fitting for the problem (e.g. maybe it should be is_same).

void Set(Tuple& val, size_t index, Variant const& elem_v)
{
    mp_with_index<std::tuple_size_v<Tuple>>(
        index,
        [&](auto I){
            std::visit([&](auto const& alt){
                if constexpr (std::is_assignable_v<
                        std::tuple_element_t<Tuple, I>,
                        decltype(alt)>)
                {
                    std::get<I>(val) = alt;
                } else {
                    throw /* something */;
                }
            }, elem_v);
        });
}

如果您要求 Tuple Variant 中恰好出现一次,并且您只想直接从该类型进行赋值而不进行任何转换,可以简化为:

If you require that every type in the Tuple appears exactly once in the Variant, and you want to directly only assign from that type without doing any conversions, this can be simplified to:

void Set(Tuple& val, size_t index, Variant const& elem_v)
{
    mp_with_index<std::tuple_size_v<Tuple>>(
        index,
        [&](auto I){
            using T = std::tuple_element_t<Tuple, I>;
            std::get<I>(val) = std::get<T>(elem_v);
        });
}

如果变量未使用该类型,则会抛出该错误。

which will throw if the variant is not engaged with that type.

这篇关于获取一个std :: tuple元素作为std :: variant的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆