2

C++ でのコード生成の大きな用途の 1 つは、メッセージのシリアル化をサポートすることです。通常、同じステップでメッセージのコンテンツとレイアウトの指定をサポートし、通信ストリームとの間でシリアル化できるオブジェクトを提供できるそのメッセージ タイプのコードを生成します。これまでは、通常、次のようなコードが生成されていました。

class MyMessage : public SerialisableObject
{
  // message members
  int myNumber_;
  std::string myString_;
  std::vector<MyOtherSerialisableObject> aBunchOfThingsIWantToSerialise_;

public:
  // ctor, dtor, accesors, mutators, then:

  virtual void Serialise(SerialisationStream & stream)
  {
    stream & myNumber_;
    stream & myString_;
    stream & aBunchOfThingsIWantToSerialise_;
  }
};

この種の設計を使用する際の問題は、優れたアーキテクチャの重要なルールに違反することです。つまり、設計の意図を 2 回指定する必要はありません。重複したコードやその他の一般的な開発の重複など、意図の重複により、コード内の 1 つの場所が他の場所と発散する余地が生じ、エラーが発生します。

上記では、複製はメンバーのリストです。潜在的なエラーには、メンバーをクラスに追加したが、それをシリアライゼーション リストに追加するのを忘れている、メンバーを 2 回シリアライズしている (メンバー宣言と同じ順序を使用していない、または同様のメンバーのスペル ミスが原因である可能性があります) などがあります。 、またはメンバーではないものをシリアル化します (名前の検索で、検索規則に一致するオブジェクトとは異なるスコープで何かが見つからない限り、コンパイラ エラーが発生する可能性があります)。この種の間違いは、すべてのヒープ割り当てを (スマート ポインターを使用する代わりに) 削除と一致させたり、(RAII ctor//dtor メカニズムを使用して) ファイルを閉じて開いたりすることをもはや試みないのと同じ理由です。

したがって、一般的に、これはコード生成で処理できるものの 1 つです。ファイル MyMessage.cg を作成して、レイアウトとメンバーの両方を 1 つのステップで指定することができます。

serialisable MyMessage
{
  int myNumber_;
  std::string myString_;
  std::vector<MyOtherSerialisableObject> aBunchOfThingsIWantToSerialise_;
};

コード生成ユーティリティを介して実行され、コードが生成されます。

外部コード生成なしで c++0x でこれを行うことがまだ可能かどうか疑問に思っていました。クラスを一度シリアライズ可能として指定できるようにする新しい言語メカニズムはありますか?そのメンバーの名前とレイアウトは、シリアライズ中にメッセージをレイアウトするために使用されますか?

明確にするために言うと、c++0x より前の言語でも、この種の動作に近づくことができるブースト タプルとフュージョンのトリックがあることを私は知っています。ただし、これらの使用法は、メンバー名によるアクセスではなくタプルへのインデックス付けに基づいているため、メッセージにアクセスするコード内の他の場所も並べ替える必要があるため、レイアウトを変更することはすべて脆弱です。メッセージを使用するコード内の場所でレイアウト仕様を複製する必要がないように、ある種のメンバー名によるアクセスが必要です。

また、これを次のレベルに引き上げて、一部のメンバーをいつシリアライズしてはならないかを指定するように依頼するとよいかもしれません。組み込みのシリアライゼーションを提供する他の言語は、多くの場合、これを行うための何らかの属性を提供します。自然に見えるかもしれません。ただし、メッセージの有効期間は、他のデータの有効期間とは別に、通信レイヤーとの間のトランスポートにあるため、すべてがシリアル化されていないシリアル化可能なオブジェクトを持つのは悪い設計だと個人的には思います。また、そのメンバーのように純粋にシリアライズ可能なオブジェクトを持つこともできます。そのため、そのような機能は、言語がまだ提供していないものではありません。

これは可能ですか?それとも、標準化委員会はこの種の内省機能を除外したのでしょうか? 上記のコード gen ファイルのようにする必要はありません。コンパイル時にレイアウトとメンバーを 1 つのステップで指定する簡単な方法を使用すれば、この一般的な問題を解決できます。

4

2 に答える 2

2

これは C++11 でも可能で実用的です。実際、C++03 でも可能でしたが、構文が少し扱いに​​くかったのです。同じアイデアに基づいて小さなライブラリを作成しました-以下を参照してください。

www.github.com/molw5/framework

サンプル構文:

class Object : serializable <Object,
    value <NAME(“Field 1”), int>,
    value <NAME(“Field 2”), float>,
    value <NAME(“Field 3”), double>>
{
};

基礎となるコードのほとんどは、原則として C++03 で再現できました。可変引数テンプレートを使用しない実装の詳細の一部は...トリッキーでしたが、コア機能を回復することは可能だったと思います。C++03 で再現できなかったのは、上記の NAME マクロであり、構文はかなり大きく依存しています。マクロは、文字列から一意の型名を生成するために必要な機構を提供します。これは次のとおりです。

NAME(“Field 1”)

に展開します

 type_string <'F', 'i', 'e', 'l', 'd', ' ', '1'>

いくつかの一般的なマクロと constexpr (文字抽出用) を使用します。C++03 では、上記の type_string に似たものを手動で入力する必要がありました。

于 2012-12-24T04:47:49.513 に答える
1

C++ は、どのような形式であっても、イントロスペクションもリフレクションもサポートしていません (両者が異なるという点で)。

シリアル化を手動で (つまり、イントロスペクションやリフレクションなしで) 行うことの利点の 1 つは、オブジェクトのバージョン管理を提供できることです。古い形式のシリアライゼーションをサポートし、古いバージョンにはなかったデータに対して合理的なデフォルトを作成するだけです。または、新しいバージョンで一部のデータが削除された場合は、単純にシリアル化して破棄できます。

必要なのは Boost.Serialization のようです。

于 2011-08-23T02:45:34.860 に答える