2012-05-08 10 views
11

構造体またはクラスのostream < <演算子を自動生成するツールはありますか? (One Debug-Print function to rule them allから取られた)構造体/クラスのストリーム演算子を自動生成

入力:

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のスクリプトが好ましいであろう。

+0

自動クラスのシリアル化ツールを試してみる人もいます。どのような形式の演算子<<の出力があなたに関係していますか? – johnathon

+0

JSON、XML、人間が読むことができるものはすべて私には問題ありません。 –

+0

あなたは*おそらくそれを高めるPP&MPL – David

答えて

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などの正規表現を見てください。 このソリューションの主な既定は、構造の "オフライン"、つまり何かを変更するたびに実行する必要があるということです。

Benoit。

+0

主な問題は、退屈で退屈な作業であるため、私は自分自身でserializeメソッドを記述したくないということです。出力したいすべての構造体はシンプルなので、serialize()またはoperator <<()コードを自動生成します。 –

1

これを達成するには、ソースファイルで実行する外部ツールを使用するしかありません。

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

しかし、それはあなたが持っている構造体の数によって異なります。手動で演算子を書くほうが良いですが、数百の構造体がある場合は、(de)直列化演算子ジェネレータを記述したいかもしれません。

3

これには、C++を正確に解析し、さまざまなクラス/構造体を列挙し、クラス/構造体ごとに「シリアライゼーション」を決定し生成し、正しい場所 "(おそらく構造体が見つかったのと同じ範囲)。実際のコードでディレクティブを展開するには、完全なプリプロセッサが必要です。

DMS Software Reengineering ToolkitC++11 front endの組み合わせが可能です。 DMSは、汎用構文解析/ AST構築、シンボルテーブル構築、フローおよびカスタム解析、変換およびソースコード再生成機能を提供することにより、カスタムツールの構築を可能にする。 C++のフロントでは、DMSがC++を解析して正確なシンボルテーブルを作成するだけでなく、修正または新しい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を構築し、構造体の全体関数に挿入します。

2

これを行うには、主に二つの方法があります:メタプログラミングテクニクス

を使用して(例えばクランバインディングにフックアップPythonスクリプトなど)外部解析ツール

  • を使用して

    • は...もちろんそれらは混在することができます。

      私はClang Pythonバインディングについての知識が十分ではないので、メタポグラミングに専念します。


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

      メタプログラミングとランタイム操作を簡単に混在させるには、ライブラリを再生する方が簡単です(Boost.Fusion)。

      あなたの構造が、その属性がBoost.Fusionシーケンスの観点から説明されるように調整されている場合、シーケンス上にたくさんのアルゴリズムを自動的に適用することができます。ここではassociate sequenceが最適です。

      我々はメタプログラミングを話しているので、the map入力した値タイプを関連付けます。

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


      私はそれがしばらくしているという理由だけで、詳細をごまかすだろうと私は、構文が関与して覚えていないが、基本的な考え方はに取得することです:構文です

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

      Fusionの地図とそれに関連するタグを宣言する砂糖:

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

      次に、属性に適用される必要があるすべての操作はで簡単に構築することができます

  • +0

    @MatthieM:Diは、外部のソリューションを好みます。そこに構造体を貼り付け、生成したオペレータコードをコピーしてコピーします。私が出力したい構造体のほとんどは外部ライブラリにあります。 –

    +0

    @ChristopherOezbek:私はこのような(統合された)ツールを知りませんが、私は思っていますが、DMS(Iraの回答)に支払う必要がない場合は、Clangプロジェクトに興味を持ってください。 libclangを使用すると、C++ファイルを解析してASTで操作できます。あなたはclang devのメールリストで特定の質問をすることができます。 –

    +0

    @MatthieM:ありがとう! Boost :: Fusionは私の別のプロジェクトに興味があります! –

    関連する問題