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

Map オブジェクトをどのように定義すればよいですか? この機能を使用するには、どのような秘教が必要ですか? 単純なテンプレート? ブーストのもの?いくつかのオフセットトリック?Qバリアント何とか?

注:残念ながら、Qt のプロパティ システムはオプションではありません。


編集:私の要求の奇妙な性質について:どこか、たとえばデバイスからデータフレームを受け取ります。データの最初の 4 バイトは、フレームのタイプを指定します。したがって、このデータを受け取るたびに、それを Device 構造体の対応するメンバー変数に入れる必要があります。何百もの異なるデータ型があり、この種のマッチングを複数の場所で使用する必要があるため、単調な作業を取り除きたい、または少なくとも一度はやりたいと思いました ("if/else" と "switch"声明)。

4

1 に答える 1

0

更新:あなたの質問に対する他の回答を参照してください。各データ フレームをツリー データ モデルの独自の要素に配置する方がはるかにクリーンです。そのような要素の子は、フレーム内のデータ メンバーになります。これは、さまざまな数の要素を持つさまざまなフレームの状況に一致します。各フレームに同じ数の要素がある場合は、テーブル モデルの方が適しています。Qt のモデル ビュー システムは、すべてのデータに QVariants を使用し、任意の複雑なモデルにインデックスを付ける手段を提供します。

内部的には引き続き構造を使用してデータを保持できますが、少なくともグローバル (外部) 構造を固定する必要はありません。プロトタイプ モデルを作成するとき、各最上位要素 (たとえば、一番上の行) にそのデータ型を割り当てて、基礎となるデータ構造などを内部的に作成することができます。

元のアプローチに戻ります。

QVariant のようなアプローチが機能し、整数キーがランタイム プロパティである場合に実際に機能させる唯一の方法です。整数キーをコンパイル時にのみ有効にしたい場合は、もちろん、整数に特化したテンプレート化された関数/ファンクター/クラスメンバーがそのトリックを行います。

値がバリアントに割り当てられたので、「バリアント」は割り当てをターゲット メンバーに転送する必要があります。

theMap は、任意のコンテナ タイプにすることができます。機能は「バリアント」にあります。これは基本的に変数のハンドルであるため、Handle と呼びましょう。

変換をサポートするコーディングを行うことができます。たとえば、double ハンドルで整数の代入を許可すると便利な場合があります。

繰り返しますが、これは本当に邪悪なデザインであり、それほど壊れたものは必要ないと思います。アンチパターンです。それは叫びます:誰かが台無しにしました。やらないでください。

以下は、最も単純な実装です。

#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;
}
于 2012-06-25T01:53:09.873 に答える