c++ - 使用 C++17 中声明的联合初始化 C 结构
问题描述
这个问题专门针对C++17中的选项。假设 C 库中的以下声明(我无法更改它们):
typedef enum {
TYPEA = 0,
TYPEB = 2,
TYPEC = 4
} SPECIFIC_TYPE_t;
typedef struct {
uint16_t Method : 1;
uint16_t Access : 2;
uint16_t VendorSpecific : 1;
uint16_t Direction : 1;
uint16_t Persistent : 1;
uint16_t Internal : 4;
uint16_t Reserved : 6;
} PROPERTY_t;
typedef RESULT_t (*CB_DataPointRead_t) (void *Service, uint8_t Pinpoint, bool VendorSpecific,
uint16_t GroupID, uint16_t ElementID, void *Data,
uint8_t *DataLengthInOut);
typedef RESULT_t (*CB_DataPointWrite_t) (void *service, uint8_t Pinpoint, bool VendorSpecific,
uint16_t GroupID, uint16_t ElementID, void *Data,
uint8_t DataLength);
typedef struct {
uint16_t GroupID;
uint16_t ElementID;
uint8_t Pinpoint;
SPECIFIC_TYPE_t Type;
uint8_t Size;
PROPERTY_t Property;
union {
struct {
CB_DataPointRead_t Read;
CB_DataPointWrite_t Write;
} Callback;
struct {
void *Data;
} DirectAccess;
} AccessType;
} DataPoint_t;
纯 C 中的状态
初始化最后一个元素指示符初始化器在 C 中运行良好:
uint16t dataPointValue = 0;
const DataPoint_t firstDatapointConfig = {
/*...*/,
.DirectAccess = { (void*)&dataPointValue; }
};
C++ 中的指示符初始值设定项
它们出现在 C++20 中,在许多方面与 C 不兼容。
问题
我firstDatapointConfig
想像 C++17 中的 const 一样初始化变量。到目前为止,除了在 C 中编写函数(编译为 C 代码)并在使用前将初始化结构返回给变量之外,我没有看到其他方法。我尝试了各种方法,包括处理指示符初始化程序的 gnuc++17,但它告诉我:
error: 'const DataPoint_t' has no non-static data member named 'DirectAccess'
如果没有启用 C++20,MSVC 根本不会消化这种初始化方法。
解决初始化程序之外的最后一个元素,也不起作用:
datapoint.DirectAccess = { &value };
导致以下错误:
error: 'struct DataPoint_t' has no member named 'DirectAccess'
评论
在通过 bindgen 处理它们之后,在 Rust 中使用这些结构要容易得多:-)
问题
有没有办法用填充正确值的元素初始化DataPoint_t
C++17 中的类型变量?DirectAccess
解决方案
有没有办法用填充了正确值的 DirectAccess 元素初始化 C++17 中的 DataPoint_t 类型的变量?
是的,尽管我的做法有点麻烦。可能有更简单的方法:
// Make a usable type of that anonymous entity:
using AccessType_t = decltype(DataPoint_t::AccessType);
// Use the new type and prepare what you need:
AccessType_t at;
at.DirectAccess.Data = nullptr;
// initialize your DataPoint_t
const DataPoint_t firstDatapointConfig{1,2,3,TYPEA,4, PROPERTY_t{}, at};
如果你经常这样做,你可以创建一个辅助函数:
using AccessType_t = decltype(DataPoint_t::AccessType);
using Callback_t = decltype(AccessType_t::Callback);
using DirectAccess_t = decltype(AccessType_t::DirectAccess);
template<class U>
constexpr auto init_AccessType(U u) {
AccessType_t at;
if constexpr (std::is_same_v<U,Callback_t>) {
at.Callback = u;
} else if constexpr (std::is_same_v<U,DirectAccess_t>) {
at.DirectAccess = u;
} else {
// uninitialized
}
return at;
}
const DataPoint_t firstDatapointConfig{1,2,3,TYPEA,4, PROPERTY_t{},
init_AccessType(DirectAccess_t{nullptr})};
推荐阅读
- laravel - Laravel 8: Illuminate\Database\QueryException: SQLSTATE[22P02]: Invalid text representation: 7 ERROR: invalid input syntax for type integer
- c - 为什么有未定义的引用?
- ruby-on-rails - Rails 的 Grape API:Get 中的 JSON Request.Body 参数
- c# - 将 JSON 本地文件反序列化为转换为 DataTable 的 List
- python - 从 python shell 导入自己的 *.py 文件
- oracle - 按日期精度划分的 Oracle 分区范围
- rust - 如何将变量的资源推入向量但使其保持活动状态
- reactjs - 使用 AWS Lightsail 进行 Web 部署
- php - 如何在刀片上显示保存在存储文件夹中的图像
- python - 从列表中创建数据框并保留重复项