Domanda

In ANSI C ++, come posso assegnare lo stream cout a un nome di variabile? Quello che voglio fare è, se l'utente ha specificato un nome per il file di output, invio l'output lì, altrimenti lo invio allo schermo. Quindi qualcosa del tipo:

ofstream outFile;
if (outFileRequested) 
    outFile.open("foo.txt", ios::out);
else
    outFile = cout;  // Will not compile because outFile does not have an 
                     // assignment operator

outFile << "whatever" << endl;

Ho provato a farlo anche come funzione Macro:

#define OUTPUT outFileRequested?outFile:cout

OUTPUT << "whatever" << endl;

Ma questo mi ha dato anche un errore del compilatore.

Suppongo che potrei usare un blocco IF-THEN per ogni uscita, ma vorrei evitarlo se potessi. Qualche idea?

È stato utile?

Soluzione

Usa un riferimento. Si noti che il riferimento deve essere di tipo std :: ostream , non std :: ofstream , poiché std :: cout è un std :: ostream , quindi è necessario utilizzare il minimo comune denominatore.

std::ofstream realOutFile;

if(outFileRequested)
    realOutFile.open("foo.txt", std::ios::out);

std::ostream & outFile = (outFileRequested ? realOutFile : std::cout);

Altri suggerimenti

Suppongo che il tuo programma si comporti come strumenti standard unix, che quando non viene dato un file scriverà sullo standard output, e quando viene dato un file scriverà in quel file. Puoi reindirizzare cout per scrivere in un altro buffer di flusso. Finché il reindirizzamento è attivo, tutto ciò che è stato scritto su cout è scritto in modo trasparente nella destinazione designata. Una volta che l'oggetto di reindirizzamento esce dall'ambito, lo stream originale viene inserito e l'output scriverà di nuovo sullo schermo:

struct CoutRedirect { 
    std::streambuf * old; 
    CoutRedirect():old(0) {
        // empty
    }

    ~CoutRedirect() {
        if(old != 0) {
            std::cout.rdbuf(old);
        }
    }

    void redirect(std::streambuf * to) {
        old = std::cout.rdbuf(to);
    }
}

int main() {
    std::filebuf file;
    CoutRedirect pipe;
    if(outFileRequested) {
        file.open("foo.txt", std::ios_base::out);
        pipe.redirect(&file);
    }
}

Ora, cout viene reindirizzato al file fintanto che la pipe è viva in main. Puoi renderlo più "pronto per la produzione" rendendolo non copiabile, perché non è pronto per essere copiato: se la copia non rientra nell'ambito di applicazione, ripristinerebbe già lo stream originale.

Puoi trovare una spiegazione molto dettagliata di come farlo qui: http://groups.google.com/group/ comp.lang.c ++ / msg / 1d941c0f26ea0d81? pli = 1

Speriamo che qualcuno lo scriva in modo più chiaro affinché lo stack overflow prenda i punti ...

Seguendo le tracce di Adam Rosenfield , ma risolvendo il problema di inizializzazione di riferimento con operatori ternari e virgola:

bool outFileRequested = false;

std::ofstream realOutFile;
std::ostream & outFile = outFileRequested
    ? realOutFile.open("foo.txt", std::ios::out), realOutFile
    : std::cout;

outFile << "some witty remark";

(Testato in VS)

Penso che Adam sia sulla buona strada ma non credo che tu possa assegnare riferimenti - devi invece usare un puntatore:

std::ofstream realOutFile;
std::ostream * poutFile;

if(outFileRequested)
{
    realOutFile.open("foo.txt", std::ios::out);
    poutFile = &realOutFile;
}
else
    poutFile = &std::cout;

potresti quindi definire un riferimento come valore del puntatore, ma non sarebbe globale

std::ostream & outFile = *poutFile;

Non sono sicuro che tu possa assegnare cout a una variabile di tipo ofstream. cout è un oggetto di tipo ostream (mentre cin è di tipo istream) e non sono sicuro che l'uno erediti dall'altro. Quindi, forse qualcosa che controlla per vedere se un file è stato dato / esiste e creare il tipo di flusso appropriato sarebbe un approccio migliore.

Ci sono volute circa due ore per arrivare. Fondamentalmente, ho una classe esterna che esegue una suite di test. Mando un delegato per eseguire i test, quindi per poter accedere all'output devo inviare un flusso di output. Immagino che avrei potuto fare un flusso diverso per test. In ogni caso, volevo passare nel ofstream per essere usato in seguito.

// Main code to create Test Suite Object
ofstream debugFile("debug.txt");
TestSuiteObject* myTestSuite = new TestSuiteObject(&debugFile);

// Test Suite Object
class TestSuiteObject: public Test::Suite
{
public:
 TestSuiteObject(std::ofstream* debug) : m_debug(*debug)
 {
  m_debug << "some witty remark" << std::endl;
  TEST_ADD(TestSuiteObject::test1);
  TEST_ADD(TestSuiteObject::test2);
  TEST_ADD(TestSuiteObject::test3);

 }

 void test1();
 void test2();
 void test3();

private:
 std::ofstream& m_debug;
};
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top