关于 std::variant 的一般问题
General questions about std::variant
我对新 std::variant 类型有一些疑问。我考虑过将它用作 union 的类型安全替代方案。我写了一些应该在在线编译器中编译的测试代码。我没有找到很多关于 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] 的联合)。
非常感谢。
您可以 assign/initialize 一个 std::variant
直接使用您想要放置的类型的纯右值:
parameters_t comParameters = std::array<uint8_t, 4>{};
尽管与您的代码相比,此零初始化数组。
如果想避免这里涉及的copy/move构造,可以使用
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_if
returns 指向 std::variant
中对象的 指针 。它从不复制对象。
您也可以使用 std::get
而不是 std::get_if
。如果您尝试访问错误的类型 std::get
并且 returns 对包含的对象 引用 将抛出异常。它也从不复制对象。:
auto& parameterReference1 = std::get<std::array<uint8_t, 4>>(comParameters);
std::variant
类型列表中不允许内置数组类型或引用类型或函数类型,因为类型需要满足可破坏的概念,这意味着表达式
t.~T()
其中 t
的类型 T
必须格式正确。对于内置数组而言并非如此,但对于几乎所有其他合理的对象类型都是如此。
我对新 std::variant 类型有一些疑问。我考虑过将它用作 union 的类型安全替代方案。我写了一些应该在在线编译器中编译的测试代码。我没有找到很多关于 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] 的联合)。
非常感谢。
您可以 assign/initialize 一个 std::variant
直接使用您想要放置的类型的纯右值:
parameters_t comParameters = std::array<uint8_t, 4>{};
尽管与您的代码相比,此零初始化数组。
如果想避免这里涉及的copy/move构造,可以使用
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_if
returns 指向 std::variant
中对象的 指针 。它从不复制对象。
您也可以使用 std::get
而不是 std::get_if
。如果您尝试访问错误的类型 std::get
并且 returns 对包含的对象 引用 将抛出异常。它也从不复制对象。:
auto& parameterReference1 = std::get<std::array<uint8_t, 4>>(comParameters);
std::variant
类型列表中不允许内置数组类型或引用类型或函数类型,因为类型需要满足可破坏的概念,这意味着表达式
t.~T()
其中 t
的类型 T
必须格式正确。对于内置数组而言并非如此,但对于几乎所有其他合理的对象类型都是如此。