2012-12-12 14 views
9

Sto riscontrando qualche problema nel tentativo di implementare una classe di stream personalizzata per generare codice ben codificato in un file di output. Ho cercato estensivamente online ma non sembra esserci un consenso sul modo migliore per raggiungere questo obiettivo. Alcune persone parlano di derivare il flusso, altri parlano derivante buffer, altri ancora suggeriscono l'uso di locali/sfaccettature eccC++ flusso di output personalizzato con rientranza

In sostanza, mi sto trovando a scrivere un sacco di codice come questo:

ofstream myFile(); 
myFile.open("test.php"); 
myFile << "<html>" << endl << 
      "\t<head>" << endl << 
      "\t\t<title>Hello world</title>" << endl << 
      "\t</head>" << endl << 
      "</html>" << endl; 

Quando le schede iniziano a sommare sembra orribile, e sembra che sarebbe stato bello avere qualcosa di simile:

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; 

cioè creare una classe di flusso derivato che tenere traccia della sua profondità di rientro corrente, poi alcuni manipolatori per aumentare/diminuire il rientro profondità e un manipolatore per scrivere una nuova riga seguita da molte schede.

Quindi, ecco il mio colpo ad attuare la classe & manipolatori:

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; 
} 

Questo costruisce, ma non genera i risultati attesi ; qualsiasi tentativo di usare i manipolatori personalizzati fa sì che vengano lanciati su un booleano per qualche motivo e "1" scritto sul file. Devo sovraccaricare l'operatore < per la mia nuova classe? (Non sono stato in grado di trovare un modo per fare ciò che costruisce)

Grazie!

p.s.

1) Ho omesso il #include, utilizzando lo spazio dei nomi ecc. Dai frammenti di codice per risparmiare spazio.

2) Sto mirando ad essere in grado di utilizzare un'interfaccia simile a quella del mio secondo frammento di codice. Se dopo aver letto tutto il post, pensi che sia una cattiva idea, spiegami perché e fornisci un'alternativa.

+1

Domanda: se il risultato desiderato è codice pulito e output corretto, ovvero se questo non è solo accademico o per il tuo miglioramento, perché scrivere [HT | X] ML direttamente in questo modo? Come minimo, potresti scriverlo su disco UNindented, quindi usare qualche prettifier (in ordine, per esempio) per fare questo sporco lavoro. ... detto questo, è interessante, e ho una sensazione untuosa che starò mettendo insieme una soluzione insieme. :) – Christopher

+0

Ciao - questa è una buona idea e probabilmente quello che finirò se non riuscirò a far funzionare il Piano A. Trovo che gli stream siano uno degli aspetti più confusi del C++, quindi ho pensato che questo potesse essere un buon modo per capire meglio come funzionano ... – user1898153

risposta

8

Gli iostreams supportano l'aggiunta di dati personalizzati, quindi non è necessario scrivere una classe derivata completa solo per aggiungere un livello di indentazione che verrà gestito dai manipolatori. Questa è una caratteristica poco conosciuta degli iostreams, ma è utile qui.

Si potrebbe scrivere i manipolatori come questo:

/* 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

ho combinato soluzione di Bart van Ingen Schenau con una sfaccettatura, per consentire a spingere e popping dei livelli di rientro per i flussi in uscita esistenti. Il codice è disponibile su GitHub: https://github.com/spacemoose/ostream_indenter, e c'è una più approfondita demo/test nel repository, ma in fondo ti permette di effettuare le seguenti operazioni:

/// 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; 

produrre:

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

ho avuto fare una specie di trucco sgradevole, quindi sono interessato a ricevere feedback sull'utilità dei codici.