我们继承了旧代码,我们正在转换为现代C++以获得更好的类型安全性,抽象性和其他好处.我们有许多带有许多可选成员的结构,例如:
struct Location {
int area;
QPoint coarse_position;
int layer;
QVector3D fine_position;
QQuaternion rotation;
};
Run Code Online (Sandbox Code Playgroud)
重要的是,所有成员都是可选的.至少有一个将出现在任何给定的位置实例中,但不一定全部存在.可能有更多的组合可能比原始设计师显然方便表达每个单独的结构.
结构以这种方式反序列化(伪代码):
Location loc;
// Bitfield expressing whether each member is present in this instance
uchar flags = read_byte();
// If _area_ is present, read it from the stream, else it is filled with garbage
if (flags & area_is_present)
loc.area = read_byte();
if (flags & coarse_position_present)
loc.coarse_position = read_QPoint();
etc.
Run Code Online (Sandbox Code Playgroud)
在旧代码中,这些标志永久存储在结构中,并且每个结构成员的getter函数在运行时测试这些标志,以确保所请求的成员存在于给定的Location实例中.
我们不喜欢这种运行时检查系统.请求不存在的成员是一个严重的逻辑错误,我们希望在编译时找到它.这应该是可能的,因为无论何时读取位置,都知道应该存在哪些成员变量组合.
首先,我们考虑使用std :: optional:
struct Location {
std::optional<int> area;
std::optional<QPoint> coarse_location;
// etc.
};
Run Code Online (Sandbox Code Playgroud)
该解决方案使设计缺陷现代化而不是修复它.
我们想过像这样使用std :: variant:
struct Location {
struct Has_Area_and_Coarse {
int area;
QPoint coarse_location;
};
struct Has_Area_and_Coarse_and_Fine {
int area;
QPoint coarse_location;
QVector3D fine_location;
};
// etc.
std::variant<Has_Area_and_Coarse,
Has_Area_and_Coarse_and_Fine /*, etc.*/> data;
};
Run Code Online (Sandbox Code Playgroud)
当多个成员变量组合成为可能时,此解决方案使非法状态无法表示,但无法很好地扩展.此外,我们不希望通过指定Has_Area_and_Coarse来访问,而是通过更接近loc.fine_position的访问.
我们没有考虑过这个问题的标准解决方案吗?
那么 mixin 呢?
struct QPoint {};
struct QVector3D {};
struct Area {
int area;
};
struct CoarsePosition {
QPoint coarse_position;
};
struct FinePosition {
QVector3D fine_position;
};
template <class ...Bases>
struct Location : Bases... {
};
Location<Area, CoarsePosition> l1;
Location<Area, FinePosition> l2;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3199 次 |
最近记录: |