获取一个std :: tuple元素作为std :: variant

Ale*_*sky 5 c++ c++17

给定变量类型:

using Variant = std::variant<bool, char, int, float, double, std::string>;
Run Code Online (Sandbox Code Playgroud)

和一个元组类型,其中包含限于该变量类型的元素(可能有重复和省略,但不能有其他类型):

using Tuple = std::tuple<char, int, int, double, std::string>;
Run Code Online (Sandbox Code Playgroud)

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

Variant Get(const Tuple & val, size_t index);
void Set(Tuple & val, size_t index, const Variant & elem_v);
Run Code Online (Sandbox Code Playgroud)

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

编辑1:

以下示例可能阐明了我的意思:

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"));
Run Code Online (Sandbox Code Playgroud)

Bar*_*rry 7

我将继续我的主题,建议对所有元编程事物使用Boost.Mp11,因为它总有一个函数。在这种情况下,我们要mp_with_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)); }
        );
}
Run Code Online (Sandbox Code Playgroud)

鉴于在OP中,元组和变体的索引甚至不对齐,因此Set需要实际访问Variant而不是依赖索引。我在is_assignable这里使用约束,但是可以对其进行调整以适合该问题(例如,可能应该是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);
        });
}
Run Code Online (Sandbox Code Playgroud)

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

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);
        });
}
Run Code Online (Sandbox Code Playgroud)

如果变体不与该类型结合使用,则会抛出该异常。

  • @AlexeyStarinsky那是不正确的。没有这样的最大值。 (2认同)