【发布时间】:2020-03-21 15:05:46
【问题描述】:
我对新的 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,我总是会收到一份副本, 这意味着无论我怎么做,我都不能修改变量的实际值。我总是必须 在这种情况下使用 std::get_if ? 此外,与联合相比,使用 std::variant 时是否存在明显的代码膨胀或开销?特别是因为我基本上使用的是 POD 类型(uint32_t 和 uint8_t[4] 的联合)。
非常感谢。
【问题讨论】:
-
Um
get从不返回副本。对于variant、tuple、std::array或std::get被重载的任何其他类型,没有get的形式返回相关对象的副本 .我不知道你是怎么想到get复制了一些东西,尤其是当它就在函数的签名中时。 -
我在 setComParams() 函数中使用 get 而不是 get_if 并且 main() 中的值没有改变。也许错误出在其他地方。
-
@Spacefish 您的代码运行良好并给出了您想要的输出:godbolt.org/z/CFvM9q
-
好吧,你是对的。我在尝试 std::get_if 之前写了 auto paramArray = std::get ... 而不是 auto & paramArray = std::get 所以我认为这是错误的。
标签: c++ coding-style c++17 variant