2012-12-12 5 views
9

カスタムストリームクラスを実装して、出力ファイルにうっかりインデントしたコードを生成しようとすると、いくつか問題が発生します。私は広範囲にわたってオンラインで検索しましたが、これを達成するための最良の方法についてコンセンサスがないようです。インデント付きのC++カスタム出力ストリーム

ofstream myFile(); 
myFile.open("test.php"); 
myFile << "<html>" << endl << 
      "\t<head>" << endl << 
      "\t\t<title>Hello world</title>" << endl << 
      "\t</head>" << endl << 
      "</html>" << endl; 
:基本的に、私は自分自身は、このような多くのコードを書いて見つけることだ

など一部の人々は他の人がバッファを導出について話す、ストリームを導出について話す、まだ他の人がロケール/ファセットの使用を提案します

タブはそれは恐ろしい見え、このようなものを持っていいだろうようにそれはそうまで追加を開始:

ind_ofstream myFile(); 
myFile.open("test.php"); 
myFile << "<html>" << ind_inc << ind_endl << 
      "<head>" << ind_inc << ind_endl << 
      "<title>Hello world</title>" << ind_dec << ind_endl << 
      "</head>" << ind_dec << ind_endl << 
      "</html>" << ind_endl; 

すなわち、現在のインデントの深さを追跡するでしょう派生ストリームクラスを作成しますインデントを増減するマニピュレータ奥行き、マニピュレーターを使って改行を書き、多くのタブが続く。だからここ

は、クラス&マニピュレータを実装での私のショットです:

class ind_ofstream : public ofstream 
{ 
    public: 
     ind_ofstream(); 
     void incInd(); 
     void decInd(); 
     size_t getInd(); 

    private: 
     size_t _ind; 
}; 

ind_ofstream& inc_ind(ind_ofstream& is); 
ind_ofstream& dec_ind(ind_ofstream& is); 
ind_ofstream& endl_ind(ind_ofstream& is); 

ind_ofstream.h ind_ofstream.cpp

ind_ofstream::ind_ofstream() : ofstream() {_ind = 0;} 
void ind_ofstream::incInd()  {_ind++;} 
void ind_ofstream::decInd()  {if(_ind > 0) _ind--;} 
size_t ind_ofstream::getInd()  {return _ind;} 

ind_ofstream& inc_ind(ind_ofstream& is)  
{ 
    is.incInd(); 
    return is; 
} 

ind_ofstream& dec_ind(ind_ofstream& is)  
{ 
    is.decInd(); 
    return is; 
} 

ind_ofstream& endl_ind(ind_ofstream& is)  
{ 
    size_t i = is.getInd(); 
    is << endl; 
    while(i-- > 0) is << "\t"; 
    return is; 
} 

これは、構築したが、期待される出力を生成しません。 ;カスタムマニピュレータを使用しようとすると何らかの理由でブール値にキャストされ、ファイルに "1"が書き込まれます。新しいクラスに< <演算子をオーバーロードする必要がありますか? (私はビルドするこれを行う方法を見つけることができませんでした)

ありがとう!

p.s.

1)スペースを節約するために、コードスニペットからnamespaceなどを使用して#includeを省略しました。

2)2番目のコードスニペットに似たインターフェイスを使用できるようにすることを目指しています。投稿全体を読んだら、それが悪い考えだと思うなら、理由を説明して、代替案を提示してください。

+1

質問:希望の成果がクリーンなコードであり、正しい結果が得られた場合、つまりこれが単なる学問ではない場合や自分自身の改善のために[HT | X] MLを直接このように書くのはなぜですか?少なくとも、あなたはそれをUNndentedディスクに書き込んでから、この汚い作業を行うためにいくつかのプリティファイヤー(例えば、きちんとしたもの)を使用することができます。 ...と言われて、それは面白いです、私はすぐに一緒に解決策をcobblingされる脂っこい感じがあります。 :) – Christopher

+0

こんにちは - これは良いアイデアだと思うし、もし私がプランAを稼働させることができなければ、私はやってしまうだろう。私はストリームがC++のより混乱しやすい側面の1つであることがわかったので、これは彼らがどのように動作するかをより深く理解する良い方法かもしれないと思いました... – user1898153

答えて

8

iostreamsはカスタムデータの追加をサポートしているため、マニピュレータで操作されるインデントレベルを追加するためだけに完全な派生クラスを作成する必要はありません。これはあまり知られていないiostreamの機能ですが、ここでは便利です。

あなたはこのようなあなたのマニピュレータを記述します。私は、既存の出力ストリームにプッシュし、インデントレベルのポッピングできるように、面とのバートバン隠元Schenauのソリューションを組み合わせている

/* Helper function to get a storage index in a stream */ 
int get_indent_index() { 
    /* ios_base::xalloc allocates indices for custom-storage locations. These indices are valid for all streams */ 
    static int index = ios_base::xalloc(); 
    return index; 
} 

ios_base& inc_ind(ios_base& stream) { 
    /* The iword(index) function gives a reference to the index-th custom storage location as a integer */ 
    stream.iword(get_indent_index())++; 
    return stream; 
} 

ios_base& dec_ind(ios_base& stream) { 
    /* The iword(index) function gives a reference to the index-th custom storage location as a integer */ 
    stream.iword(get_indent_index())--; 
    return stream; 
} 

template<class charT, class traits> 
basic_ostream<charT, traits>& endl_ind(basic_ostream<charT, traits>& stream) { 
    int indent = stream.iword(get_indent_index()); 
    stream.put(stream.widen('\n'); 
    while (indent) { 
     stream.put(stream.widen('\t'); 
     indent--; 
    } 
    stream.flush(); 
    return stream; 
} 
0

。コードはgithubの上で提供されています:https://github.com/spacemoose/ostream_indenter、およびリポジトリ内より徹底的なデモ/テストがありますが、基本的にそれはあなたが次の操作を行うことができます:

/// This probably has to be called once for every program: 
// http://stackoverflow.com/questions/26387054/how-can-i-use-stdimbue-to-set-the-locale-for-stdwcout 
std::ios_base::sync_with_stdio(false); 

std::cout << "I want to push indentation levels:\n" << indent_manip::push 
      << "To arbitrary depths\n" << indent_manip::push 
      << "and pop them\n" << indent_manip::pop 
      << "back down\n" << indent_manip::pop 
      << "like this.\n" << indent_manip::pop; 

が生成するには:

I want to push indentation levels: 
    To arbitrary depths 
     and pop them 
    back down 
like this. 

私が持っていました厄介なやり方をするために、私はcodesユーティリティのフィードバックを聞くことに興味があります。

関連する問題