2012-03-09 2 views
6

出力ファイルの書式に新しいフラグを作成する必要があります。私はクラスC++ fstream - 独自の書式設定フラグを作成する

class foo{ 
    bar* members; 
    ofstream& operator<<(ofstream&); 
    ifstream& operator>>(ifstream&); 
}; 

を持っていると私は好きで、それを使用したい:これはXMLファイルを保存します

fstream os('filename.xml'); 
foo f; 
os << xml << f; 
os.close(); 

fstream os('filename.json'); 
foo f; 
os << json << f; 
os.close(); 

このJSONファイル。

どうすればいいですか?

答えて

6

:あなたはすべてのファイルで同じだいくつかのヘッダーやフッターが必要な場合は、単にコンストラクタとデストラクタを使用し、書きます新しいストリーム固有の メモリを取得します。 (Fooの実装ファイルに:

static int const manipFlagId = std::ios_base::xalloc(); 

enum 
{ 
    fmt_xml,  // Becomes the default. 
    fmt_json 
}; 

std::ostream& 
xml(std::ostream& stream) 
{ 
    stream.iword(manipFlagId) = fmt_xml; 
    return stream; 
} 

std::ostream& 
json(std::ostream& stream) 
{ 
    stream.iword(manipFlagId) = fmt_json; 
    return stream; 
} 

std::ostream& 
operator<<(std::ostream& dest, Foo const& obj) 
{ 
    switch (dest.iword(manipFlagId)) { 
    case fmt_xml: 
     // ... 
     break; 
    case fmt_json: 
     // ... 
     break; 
    default: 
     assert(0); // Or log error, or abort, or... 
    } 
    return dest; 
} 

あなたのヘッダーにxmljsonを宣言し、ジョブが実行され

(これを言って、私はむしろ、これは虐待のビットだと思います。 マニピュレータ。XMLなどの形式は、単純な、ローカルの書式を越えて行く、と は最高ostreamを所有している別のクラスによって処理され、そして だけで個々のオブジェクトをストリーム全体を書き込み、そしてません。)

0

頭に浮かぶ最も簡単な方法は、タグの種類とその単一のインスタンスを作成することにより開始することです:

struct JsonStreamTag {} json; 

次に、このようなタグは、ストリームをラップするオブジェクトを作成してみましょう:

class JsonStream { 
public: 

    // (1) 
    friend JsonStream operator<<(std::ostream& ostream, const JsonStreamTag&) { 
     return JsonStream(ostream); 
    } 

    // (2) 
    template<class T> 
    friend JsonStream& operator<<(JsonStream& json_stream, const T& value) { 
     write_json(json_stream.ostream, value); // (3) 
     return json_stream; 
    } 

protected: 

    JsonStream(std::ostream& ostream) : ostream(ostream) {} 

private: 

    std::ostream& ostream; 

}; 

some_ostream << json(1)のみを使用してJsonStreamを構築できることを保証するために、コンストラクタはprotectedです。他の挿入演算子(2)は実際の書式設定を行います。 (2)を省略し、代わりにoperator<<(JsonStream&, T)のためのオーバーロードを追加し、また

void write_json(std::ostream& stream, int value) { 
    stream << value; 
} 

void write_json(std::ostream& stream, std::string value) { 
    stream << '"' << escape_json(value) << '"'; 
} 

// Overloads for double, std::vector, std::map, &c. 

:あなたはその後、すべての関連するタイプのために(3)write_json()のオーバーロードを定義します。

次に、対応するXmlStreamを書き込んで、XmlStreamTagwrite_xml()を使用して、同じプロセスを実行します。これは、あなたが書いている特定の値からあなたの出力を完全に構築できることを前提としています。あなたは簡単に既存の フラグをハイジャックかにstd::ios_base::xallocのいずれかを使用して、ヨール独自のマニピュレータを作成することができます

XmlStream(std::ostream& ostream) : ostream(ostream) { 
    ostream << "<?xml version=\"1.0\"?><my_document>" 
} 

~XmlStream() { 
    ostream << "</my_document>"; 
} 
+1

私はこれがとても良いアイデアだとは思わない。 'out << json <<"ヘッダのようなものでは機能しません: "<< obj;" (もちろん、XMLのようなものについては、これはとにかく意味をなさないでしょうが、それはまずマニピュレータを使わないという議論です) –

+0

@JamesKanze:質問は明確に定義されていません。質問に答える目的で、私は「JSONストリーム」がすべてをJSON値として扱うことを前提にしていました。しかし、私はそのようなことが最初に間違っていると思う。 –

+0

XML(JSON、私が知る限り)はストリームではありません。それらはより複雑な構造です。無関係の型はXMLまたはJSONを 'ostream'に出力しません。ファイルレベルでストリーミングされた出力を処理するXMLまたはJSONデータ構造のインスタンスに挿入する必要があります。 –

1

この問題は、iostreamライブラリの最大の欠陥です。

James Kanzeのソリューションは、あなた自身のクラスでは機能する部分的なものですが、一般的にオブジェクトには明確なストリーミング方法が与えられています。

私の通常の手段は、ストリームに渡すことができる関数を使用して独自のラッパークラスを作成することです。xmlにはxml_node()またはxml_attribute()などのオーバーロードが含まれます。

os << xml_attribute("Id", id); 

は、属性IDをxml形式の変数に設定します。

ノードスコープも書きましたので、ノードの開始テキストを作成時にストリームに書き込んで、破棄時に自動的にクローズロジックを書き出します。

James Kanzeのソリューションに対する私の方法の利点は、それが拡張可能であることです。私は、James Kanzeの閉会のコメントは、彼が彼の解決法を支持しておらず、私のようなものをおそらく使用するだろうと示唆していると思います。

上記のソリューションでは、より多くのフォーマットを追加するには、演算子< <を編集する必要がありますが、jsonの書式設定コードは全く異なる関数セットになります。既存のコードを編集することなくそのコードを追加してください。

XMLの場合は、既存のDOMパーサーまたはSAXパーサーを使用し、iostreamをこのように直接使用することはありません。

+0

XMLを出力するためにストリームを直接使用するのは適切な解決策ではないと思います。ストリームはストリームの抽象化であり、階層的なデータ構造ではありません。 XMLを出力するためには、Xercesのようなライブラリを使います。階層構造に挿入できるもの。残りの部分について:ラッパークラスは、組み込み型や非常に複雑な構造のために珍しい書式設定が必要な場合に便利ですが、マニピュレータは多くの場合にうまく機能します。 –

+0

さらに正確に言えば(おそらくそれも同様です):世界的に異なるフォーマットへの出力は、ストリームとは異なるメカニズムで行う必要があります。カスタムマニピュレータは、すべてのタイプの出力に影響するものではなく、 。 (また、 'int'に書式設定オプションを追加することはできません)。 –

関連する問題