9

カスタムストリームクラスを実装して、出力ファイルに適切にインデントされたコードを生成しようとすると、問題が発生します。私はオンラインで広範囲に検索しましたが、これを達成するための最良の方法についてのコンセンサスはないようです。ストリームの導出について話す人もいれば、バッファの導出について話す人もいますが、ロケール/ファセットなどの使用を提案する人もいます。

基本的に、私は次のようなコードをたくさん書いていることに気づいています。

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;

つまり、現在のインデントの深さを追跡する派生ストリームクラスを作成し、次にインデントの深さを増減するマニピュレータ、および改行の後にいくつものタブを書き込むマニピュレータを作成します。

これが、クラスとマニピュレータの実装に関する私のショットです。

ind_ofstream.h

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.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」が書き込まれます。新しいクラスの<<演算子をオーバーロードする必要がありますか?(私はこれを構築する方法を見つけることができませんでした)

ありがとう!

ps

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

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

4

2 に答える 2

8

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

マニピュレータは次のように記述します。

/* 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;
}
于 2012-12-12T15:59:53.023 に答える