3

次の構造のクラスを定義したいとしましょう。

struct MyClass {
    int x;
    bool y;
    float z;
    MyClass(QVariantMap data) : x(data["x"]), y(data["y"]), z(data["z"]) {}
};

ご覧のとおり、私は QVariantMap ( std::map<std::string, boost::variant<...>>Qt に慣れていない方向けのものに似たもの) を持っており、そこからそのフィールドの知識がなくてもそのような型を構築できるようにしたいと考えています。 " マップのフィールド。

このスタイルのいくつかのクラスが必要であり、最大限の保守性 (文字列キーのタイプミスに関して)、読みやすさ、および自動化のために、定義をできるだけきれいにしたいと考えています。

次のようなマクロ構造を考えました。

DEF_CLASS(MyClass)(
    DEF_FIELD(int, x)
    DEF_FIELD(bool, y)
    DEF_FIELD(float, z)
);

フィールドのみを生成し、コンストラクターを生成したくない場合は問題はありません (逆の方法も可能ですが、前者のみを示します)。

#define DEF_CLASS(CLASSNAME) \
    struct CLASSNAME { \
    _DEF_CLASS_TAIL/*..."curry the arguments"...*/
#define _DEF_CLASS_TAIL(FIELDS) \
        FIELDS \
    }
#define DEF_FIELD(TYPE, NAME) TYPE NAME;

クラス定義を開始する最初のマクロを定義し、「カリー」手法を使用して 2 番目の括弧を 2 番目のマクロに転送します。2 番目のマクロはクラス定義 ( FIELDS) の内容を配置し、後で閉じます。このように - 私の考えもそうでした - 私はFIELDS2 番目のマクロ内にアクセスできます。

しかし、フィールドを 2 回出力するにはどうすればよいでしょうか。1 つは実際のフィールドを定義するため、もう 1 つはメンバーの初期化を出力するためです。

マクロDEF_CLASS_FIELDを 2 つの異なる方法で定義し、上記の定義コードのフィールドを、マクロ定義ごとに 1 つずつ「含める」と、それらを次々と正しく出力できることがわかっています。しかし、フィールドのリストはクラス定義内にある (そしてそうあるべき) ため、単純に何かを 2 回含めることはできません。

他のオプションはありますか?

Boost プリプロセッサ ライブラリは使用しないようにしていますが、それを使用する優れたソリューションがあれば、どうぞ。ただし、もしあれば、単純な解決策を非常に好みます。

4

1 に答える 1

1

これは、マップからの値をキャッシュする構造体を実際に構築するのではなく、最初の質問のコメントで説明されているように、マップにフィールドが含まれていることをコンストラクターでチェックするだけの例です。

#define DEF_CLASS(CLASSNAME) \
    struct CLASSNAME { \
    CLASSNAME(QVariantMap& map) {\
    _DEF_CLASS_TAIL/*..."curry the arguments"...*/
#define _DEF_CLASS_TAIL(FIELDS) \
        FIELDS \
    }};
#define CHK_FIELD(TYPE, NAME) \
    if (typeid(TYPE)!=typeid(map[#NAME])) \
    { throw std::runtime_error(#NAME" missing or wrong type");}
DEF_CLASS(MyClass)(
    CHK_FIELD(int, x)
    CHK_FIELD(bool, y)
    CHK_FIELD(float, z)
);

これにより、プリプロセッサから次のものが生成されます (astyle を実行した後)。

struct MyClass {
   MyClass(QVariantMap& map) {
      if (typeid(int) != typeid(map["x"])) {
         throw std::runtime_error("x"" missing or wrong type");
      }
      if (typeid(bool) != typeid(map["y"])) {
         throw std::runtime_error("y"" missing or wrong type");
      }
      if (typeid(float) != typeid(map["z"])) {
         throw std::runtime_error("z"" missing or wrong type");
      }
   }
};

編集: typeid の比較がこのように機能するかどうかは 100% 確信が持てませんが、機能するチェックに置き換えるのは簡単です。

于 2013-05-08T23:29:53.743 に答える