首页 > 解决方案 > 访问 std::variant 中的结构成员

问题描述

我有一个 std::variant,它有两个不同的结构作为替代。现在我需要用另一种选择的数据填充它(我在运行时知道),但它必须以某种方式,可以单独在结构中写入元素。显然,这是行不通的:

struct ContainerOne {
    uint8_t x;
};

struct ContainerTwo {
    uint8_t y;
    uint8_t z;
};

std::variant<ContainerOne, ContainerTwo> ContainerCollection;                   // CHOICE
ContainerCollection.x = 20;   // Error

还有另一种方法可以实现这一目标吗?如果我知道我想写的替代方案,也许一种方法可以告诉变体它具有哪种结构或类似的东西?

我能弄清楚的唯一方法是为变体的内存空间制作一个强制引用并使用它来写入它。问题是这没有使用变体的方法,因此不会自动设置索引。同样以相同的方式设置索引也很困难,因为索引的大小因不同的变体而异(有时是一个字节,有时是 8 个字节):

ContainerOne &ContainerOneRef = *(reinterpret_cast<ContainerOne*>(&ContainerCollection));

uint8_t* newptr = reinterpret_cast<uint8_t*>(&ContainerCollection) + sizeof(ContainerCollection) - 0x01; // jump to the end of variant and one byte back, in the case the index is 1 Byte
*newptr = 0x01;

ContainerOneRef.x = 20;

或者有没有办法找出索引的大小?

标签: c++std-variant

解决方案


您需要在运行时进行某种调度,以根据活动元素(成员函数index())的返回索引选择适当的值。例如,如果我们为每种类型提供选择并使用std::get

#include <iostream>
#include <cstdlib>
#include <variant>

struct ContainerOne {
    uint8_t x;
};

struct ContainerTwo {
    uint8_t y;
    uint8_t z;
};
              
using ContainerType = std::variant<ContainerOne, ContainerTwo>;

void init_ContainerOne(ContainerType& v) {
    std::get<ContainerOne>(v).x = 20;
    std::cout << __PRETTY_FUNCTION__ << "\n";
}

void init_ContainerTwo(ContainerType& v) {
    std::get<ContainerTwo>(v) = {};
    std::cout << __PRETTY_FUNCTION__ << "\n";
}

decltype(&init_ContainerOne) dispatch[] =  { init_ContainerOne,  init_ContainerTwo };


int main()
{
   std::variant<ContainerOne, ContainerTwo> container  = ContainerOne{};
    
   dispatch[container.index()](container);
}

C++17 提供std::visit让基础架构更易于构建


推荐阅读