12

構造体またはクラスの ostream << 演算子を自動生成するツールはありますか?

入力 ( 1 つの Debug-Print 関数から取得して、すべてを制御します):

typedef struct ReqCntrlT    /* Request control record */
{
  int             connectionID;
  int             dbApplID;
  char            appDescr[MAX_APPDSCR];
  int             reqID;
  int         resubmitFlag;
  unsigned int    resubmitNo;
  char            VCIver[MAX_VCIVER];
  int             loginID;
}   ReqCntrlT;

出力:

std::ostream& operator <<(std::ostream& os, const ReqCntrlT& r) 
{
   os << "reqControl { "
      << "\n\tconnectionID: " << r.connectionID 
      << "\n\tdbApplID: " << r.dbApplID 
      << "\n\tappDescr: " << r.appDescr
      << "\n\treqID: " << r.reqID
      << "\n\tresubmitFlag: " << r.resubmitFlag
      << "\n\tresubmitNo: " << r.resubmitNo
      << "\n\tVCIver: " << r.VCIver
      << "\n\tloginID: " << r.loginID
      << "\n}";
   return os; 
}

どのツールでも問題ありませんが、Python / Ruby スクリプトが推奨されます。

4

5 に答える 5

3

これに必要なのは、C ++を正確に解析し、さまざまなクラス/構造体を列挙し、クラス/構造体ごとに「シリアル化」を決定して生成し、生成されたコードを「適切な場所」に配置できるツールです(おそらく、構造体が見つかったのと同じスコープです)。実際のコードでディレクティブの拡張を処理するには、完全なプリプロセッサが必要です。

C++11フロントエンドを備えたDMSSoftwareReengineeringToolkitがこれを行うことができますDMSは、一般的な解析/ AST構築、シンボルテーブル構築、フローおよびカスタム分析、変換、およびソースコード再生機能を提供することにより、カスタムツールの構築を可能にします。C ++フロントにより、DMSはC ++を解析して正確なシンボルテーブルを構築し、変更されたASTまたは新しいASTをコンパイル可能なソース形式にきれいに印刷することができます。DMSとそのC++フロントエンドは、C++コードで大規模な変換を実行するために使用されています。

やりたいことをDMSに説明する必要があります。シンボルテーブルエントリを列挙し、構造体/クラスタイプ宣言かどうかを確認し、宣言のスコープ(シンボルテーブルエントリに記録)を決定し、サーフェス構文パターンを作成してASTを構築し、変換を適用して構築されたASTを挿入するのは簡単なようです。

必要なコアサーフェス構文パターンは、スロットと関数本体の構文パターンです。

 pattern ostream_on_slot(i:IDENTIFIER):expression =
   " << "\n\t" << \tostring\(\i\) << r.\i "; -- tostring is a function that generates "<name>"

 pattern ostream_on_struct(i:IDENTIFIER,ostream_on_slots:expression): declaration =
   " std::ostream& operator <<(std::ostream& os, const \i& r) 
     { os << \tostring\(\i\) << " { " << \ostream_on_slots << "\n}";
       return os; 
     }

ostream_on_slotの個々のツリーを作成する必要があります。

 pattern compound_ostream(e1:expression, e2:expression): expression
     = " \e1 << \e2 ";

これらのパターンを使用すると、構造体のスロットを列挙し、本体のostreamを作成し、それを構造体の関数全体に挿入するのは簡単です。

于 2012-05-08T13:32:36.187 に答える
2

これを行うには、主に2つの方法があります。

  • 外部解析ツール(Clangバインディングに接続されたPythonスクリプトなど)を使用する
  • メタプログラミング技術を使用する

..そしてもちろんそれらは混合することができます。

Clang Pythonバインディングについて、それらを使用して答えるのに十分な知識がないので、メタポグラムに集中します。


基本的に、あなたが求めているものは内省を必要とします。C ++は完全なイントロスペクションをサポートしていませんが、メタプログラミングのトリック(およびテンプレートマッチング)を使用すると、コンパイル時にイントロスペクション技術の限られたサブセットをサポートできます。これは私たちの目的には十分です。

メタプログラミングとランタイム操作を簡単に組み合わせるには、ライブラリを使用する方が簡単です:Boost.Fusion

Boost.Fusionシーケンスの観点から属性が記述されるように構造を微調整すると、シーケンスに多くのアルゴリズムを自動的に適用できます。ここでは、関連するシーケンスが最適です。

メタプログラミングについて話しているので、マップは型付きの値に関連付けます。

次に、 for_eachを使用してそのシーケンスを反復処理できます。


しばらく経ち、関連する構文を覚えていないという理由だけで、詳細を詳しく説明しますが、基本的には次のことを目的としています。

// Can be created using Boost.Preprocessor, but makes array types a tad difficult
DECL_ATTRIBUTES((connectionId, int)
                (dbApplId, int)
                (appDescr, AppDescrType)
                ...
                );

これは、FusionMapとそれに関連するタグを宣言するためのシンタックスシュガーです。

struct connectionIdTag {};
struct dbApplIdTag {};

typedef boost::fusion::map<
    std::pair<connectionIdTag, int>,
    std::pair<dbApplIdTag, int>,
    ...
    > AttributesType;
AttributesType _attributes;

次に、属性に適用する必要のある操作は、次の方法で簡単に作成できます。

// 1. A predicate:
struct Predicate {
    template <typename T, typename U>
    void operator()(std::pair<T, U> const&) const { ... }
};

// 2. The for_each function
for_each(_attributes, Predicate());
于 2012-05-08T13:45:40.677 に答える
1

これを実現する唯一の方法は、ソースファイルで実行する外部ツールを使用することです。

まず、c / c ++分析ツールを使用して、ソースコードから解析ツリーを取得することができます。次に、解析ツリーを取得したら、構造を検索するだけです。operator<<構造ごとに、構造のフィールドをシリアル化するオーバーロードを生成できるようになりました。dedeserialize演算子を生成することもできます。

ただし、構造の数によって異なります。1ダースの場合は演算子を手動で作成する方が適切ですが、数百の構造がある場合は、(逆)シリアル化演算子ジェネレーターを作成することをお勧めします。

于 2012-05-08T13:13:22.643 に答える
0

私はあなたの質問を2つの方法で理解しました。

プログラムの自動状態レポートを生成する場合は、Boost.Serializationを確認することをお勧めします。ただし、最初のステップとして、またはインスピレーションを得るために、コンパイル時にコードを生成することはありません。以下のコードは、後で読むことができるxmlまたはtxtファイルを生成するのに役立ちます。

typedef struct ReqCntrlT    /* Request control record */
{
  int             connectionID;
  int             dbApplID;
  char            appDescr[MAX_APPDSCR];
  int             reqID;
  int         resubmitFlag;
  unsigned int    resubmitNo;
  char            VCIver[MAX_VCIVER];
  int             loginID;

    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & connectionID;
        ar & reqID;
        ...
    }
}   ReqCntrlT;

詳細については、チュートリアルを参照してください:http ://www.boost.org/doc/libs/1_49_0/libs/serialization/doc/index.html

パラメータに名前を付けるだけでコードを「書き込もう」としている場合。次に、たとえばpythonやperlの正規表現を確認する必要があります。このソリューションの主なデフォルトは、構造が「オフライン」である、つまり、何かを変更するたびに構造を実行する必要があることです。

ブノワ。

于 2012-05-08T13:02:08.043 に答える