关于std :: variant的一般问题

时间:2020-03-21 15:05:46

标签: c++ coding-style c++17 variant

我对新的std :: variant类型有一些疑问。我考虑将其用作联合的类型安全替代方法。我写了一些应该在在线编译器中编译的测试代码。我还没有找到很多有关在std :: variant中存储std :: array之类的信息。使用std :: variant似乎无法存储原始缓冲区(例如uint8_t [4])。

#include <iostream>
#include <array>
#include <variant>
#include <array>
#include <stdint.h>
#include <typeinfo>
#include <cstdlib>
using parameters_t = std::variant<uint32_t, std::array<uint8_t, 4>>;

void setComParams(parameters_t& comParameters_, uint8_t value);

int main()
{
    std::array<uint8_t, 4> test;
    parameters_t comParameters = test; // can I assign the array here directly in some way?
    auto parametersArray = std::get_if<std::array<uint8_t, 4>>(&comParameters);
    if(parametersArray == nullptr) {
        exit(0);
    }

    auto & parameterReference1 = *parametersArray; //so I can use [] indexing
    parameterReference1[1] = 5;
    parameterReference1[3] = 6;
    std::cout << "I should be 5: " << (int)(*parametersArray)[1] << std::endl;
    std::cout << "I should be 5: " << (int)parameterReference1[1] << std::endl;
    std::cout << "I should be 6: " << (int)(*parametersArray)[3] << std::endl;
    std::cout << "I should be 6: " << (int)parameterReference1[3] << std::endl;
    setComParams(comParameters, 10);
    std::cout << "I should be 10: "<< (int)(*parametersArray)[1] << std::endl;
    std::cout << "I should be 10: "<< (int)parameterReference1[1] << std::endl;

    comParameters = 16; // this should be an uint32_t now
    auto parametersArray2 = std::get_if<std::array<uint8_t, 4>>(&comParameters);
    if(parametersArray2 == nullptr) {
        std::cout << "Everything in order" << std::endl;
    }

    uint32_t * parameterNumber = std::get_if<0>(&comParameters); // using index now
    *parameterNumber = 20;
    std::cout << "I should be 20: "<< (int)*parameterNumber << std::endl;
    setComParams(comParameters,30);
    std::cout << "I should be 30: "<< (int)*parameterNumber << std::endl;
    return 0;
}

void setComParams(parameters_t &comParameters_, uint8_t value) {
    auto comParametersArray = std::get_if<std::array<uint8_t, 4>>(&comParameters_);
    if(comParametersArray == nullptr) {
        auto comParameterValue = std::get_if<uint32_t>(&comParameters_);
        if(comParameterValue != nullptr) {
            *comParameterValue = value;
        }
    }
    else {
        auto & arrayReference = *comParametersArray;
        arrayReference[1] = value;
    }
}

只需确保我正确理解了所有内容:如果我使用std :: get,我将始终收到一份副本, 这意味着无论我怎么做,我都无法修改variant的实际值。我是否总是必须 在这种情况下使用std :: get_if? 此外,与联合相比,使用std :: variant时是否有任何明显的代码膨胀或开销?尤其是因为我实际上使用的是POD类型(uint32_t和uint8_t [4]的并集)。

非常感谢。

1 个答案:

答案 0 :(得分:2)

您可以直接使用要插入的类型的prvalue分配/初始化std::variant

parameters_t comParameters = std::array<uint8_t, 4>{};

尽管与您的代码相比,此参数将数组初始化为零。

如果要避免涉及此操作的复制/移动构造,可以使用

parameters_t comParameters(std::in_place_type<std::array<uint8_t, 4>>);

用于初始化或

comParameters.emplace<std::array<uint8_t, 4>>();

进行分配。

尽管两者仍然将std::array初始化为零。据我所知,目前尚无法在std::variant中默认初始化对象。

std::get_ifstd::variant中的对象返回 pointer 。它永远不会复制该对象。

您也可以使用std::get_if代替std::get。如果您尝试访问错误的类型并向包含的对象返回引用std::get只会引发异常。它也不会复制对象。

auto& parameterReference1 = std::get<std::array<uint8_t, 4>>(comParameters);

std::variant类型列表中不允许使用内置数组类型或引用类型或函数类型,因为要求这些类型满足可破坏的概念,即表达式

t.~T()

其中t的类型为T的格式必须正确。对于内置数组而言,情况并非如此,但对于所有其他明智的对象类型而言,情况并非如此。

相关问题