2012-06-25 59 views
0

在我的C++/QT应用我有一个结构与数以百计的变量,如下面的组织:映射迭代

struct MyStruct 
{ 
    int a1; 
    double a2; 
    struct InnerStruct 
    { 
     int b1; 
     bool b2; 
     struct InnerInnerStruct 
     { 
      char c1; 
       . 
       . 
       . 
     }; 
     InnerInnerStruct b3; 
      . 
      . 
      . 

    }; 
    InnerStruct a3; 
     . 
     . 
     . 
}; 

我想有地图的每个结构成员的地址变量,它具有整数作为键类型,所以我就可以通过它的密钥来访问它:

MyStruct ms; 
theMap[0] = &(ms.a1); 
theMap[1] = &(ms.a2); 
theMap[2] = &(ms.a3.b1); 
theMap[3] = &(ms.a3.b2); 
theMap[4] = &(ms.a3.b3.c1); 

theMap[3] = true; // MyStruct::InnerStruct::b2 is 'true' now 

应该怎么定义theMap反对呢?我需要什么样的深奥主义才能拥有这个特征?纯模板?提升东西?一些抵消技巧? QVariant以某种方式?

注意:不幸的是Qt的财产制度不是一种选择。


编辑:关于我的请求的奇怪性质:我收到数据帧从什么地方,比如说,一个设备。前四个字节的数据指定了帧的类型。所以无论何时我收到这些数据,我都必须将它放入Device结构的相应成员变量中。由于有数百种不同的数据类型,因为我需要使用这种匹配不止一个地方,我想摆脱苦差事 - 至少要做一次 - (“if/else”和“switch”语句)。

+3

为什么?使用类型擦除可能有一种方法可以做到这一点,但这主要是需要进行设计检修。 – tmpearce

+0

当你收到一个画面时,要决定如何处理它,取决于你。把它放入一个数据结构的大乱码是一种不好的方法。不要认为它是从最高处投射到你身上的,因为它是你的选择,这很糟糕,你可能不想使用如此混乱的结构来保存你的数据。拥有这种混乱的数据结构可能是非常特殊的情况,也就是说,如果你映射了一个PLC的过程映像,那么这种结构可能是一种很不相同的方式。 –

回答

0

更新:请参阅我的other answer您的问题。将每个数据框放入树数据模型的自己的元素中会更清晰。这种元素的孩子将成为框架中的数据成员。这与您具有不同数量的元素的各种帧的情况相符。如果每个框架具有相同数量的元素,则表格模型会更适合。 Qt的模型视图系统为所有数据使用QVariants,并提供将索引编入任意复杂模型的方法,所以为什么要重新发明轮子。

在内部,您仍然可以使用这些结构来保存数据,但至少您不需要具有固定的全局(外部)结构。在创建原型模型时,可以为每个顶层元素(例如顶层行)分配其数据类型,在内部创建基础数据结构等。

现在回到您的原始方法。

类似于QVariant的方法可以工作,而且这是关于如果整数键是运行时属性才能真正实现它的唯一方法。如果你希望整数键仅在编译时有用,那么当然整型专用模板函数/函子/类成员就可以做到。

现在值已分配给变体,“变体”必须将赋值转发给目标成员。

该映射可以是任何你想要的容器类型。该功能位于“变体”中。我们称它为Handle,因为它本质上是一个变量的句柄。

您可以编写代码来支持转换,例如让双处理允许整数分配可能很有用。

但让我再说一遍:这是一些非常邪恶的设计,我认为没有必要破坏任何东西。这是一个反模式。它尖叫着:有人搞砸了。不要这样做。

下面是最微不足道的实现。

#include <QMap> 
#include <QVariant> 

class Handle 
{ 
    QVariant::Type type; 
    void * address; 
public: 
    Handle() : type(QVariant::Invalid), address(0) {} 
    explicit Handle(int* p) : type(QVariant::Int), address(p) {} 
    explicit Handle(bool * p) : type(QVariant::Bool), address(p) {} 
    explicit Handle(double* p) : type(QVariant::Double), address(p) {} 
    Handle & operator=(int* p) { return *this = Handle(p); } 
    Handle & operator=(int v) { 
     if (type == QVariant::Int) { *(int*)address = v; } 
     else if (type == QVariant::Double) { *(double*)address = v; } 
     else Q_ASSERT(type == QVariant::Invalid); 
     return *this; 
    } 
    int toInt() const { Q_ASSERT(type == QVariant::Int); return *(int*)address; } 
    Handle & operator=(bool* b) { return *this = Handle(b); } 
    Handle & operator=(bool b) { 
     Q_ASSERT(type == QVariant::Bool); *(bool*)address = b; 
     return *this; 
    } 
    bool toBool() const { Q_ASSERT(type == QVariant::Bool); return *(bool*)address; } 
    Handle & operator=(double* p) { return *this = Handle(p); } 
    Handle & operator=(double d) { 
     Q_ASSERT(type == QVariant::Double); *(double*)address = d; 
     return *this; 
    } 
    int toDouble() const { Q_ASSERT(type == QVariant::Double); return *(double*)address; } 
}; 

struct MyStruct 
{ 
    int a1; 
    double a2; 
    struct InnerStruct 
    { 
     int b1; 
     bool b2; 
    } b3; 
}; 

int main() 
{ 
    MyStruct s; 
    QMap<int, Handle> map; 
    map[0] = &s.a1; 
    map[1] = &s.a2; 
    map[2] = &s.b3.b1; 
    map[3] = &s.b3.b2; 
    map[0] = 10; 
    map[1] = 1.0; 
    map[2] = 20; 
    map[3] = true; 
    return 0; 
}