2009-01-09 12 views
13

Wie kann ich in ANSI C++ den Cout-Stream einem Variablennamen zuweisen? Was ich tun möchte, ist, wenn der Benutzer einen Ausgabedateinamen angegeben hat, sende ich dort eine Ausgabe, andernfalls sende ich ihn an den Bildschirm. So etwas wie:Cout einem Variablennamen zuweisen

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; 

habe ich versucht, dies als eine Makro-Funktion zu tun, wie gut:

#define OUTPUT outFileRequested?outFile:cout 

OUTPUT << "whatever" << endl; 

Aber das gab mir auch einen Compiler-Fehler.

Ich dachte, ich könnte entweder einen IF-THEN-Block für jeden Ausgang verwenden, aber ich würde das gerne vermeiden, wenn ich könnte. Irgendwelche Ideen?

Antwort

34

Verwenden Sie einen Verweis. Beachten Sie, dass die Referenz vom Typ std::ostream, nicht std::ofstream sein muss, da std::cout eine std::ostream ist, daher müssen Sie den kleinsten gemeinsamen Nenner verwenden.

std::ofstream realOutFile; 

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

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

Das ist eine sehr elegante Lösung. Vielen Dank! – user12576

0

Ich denke Adams auf dem richtigen Weg, aber ich glaube nicht, dass Sie Referenzen zuweisen können - Sie müssen stattdessen einen Zeiger verwenden:

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

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

Sie dann eine Referenz definieren könnte der Wert sein des Zeigers, aber es wäre nicht global sein

std::ostream & outFile = *poutFile; 
+0

Sollte immer Referenzen über Zeiger bevorzugen. Und es kann mit Referenzen getan werden. Siehe oben den festen Code. –

+1

Sicher, Sie können einfach nicht eine globale Variable mit einer Referenz b/c verwenden, die Sie nicht mit dem richtigen Wert initialisieren können. – KenE

0

ich bin nicht sicher, dass Sie cout auf eine Variable vom Typ ofstream zuweisen können. cout ist ein Objekt vom Typ ostream (während cin vom Typ istream ist) und ich bin mir nicht sicher, ob man von dem anderen erbt. Also, vielleicht etwas prüfen, um zu sehen, ob eine Datei gegeben wurde/existiert und den entsprechenden Stream-Typ zu erstellen, wäre ein besserer Ansatz.

1

Nach Adam Rosenfield ‚s Spuren, aber die Referenz Initialisierungsproblem mit ternären und Komma Operatoren Befestigung:

bool outFileRequested = false; 

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

outFile << "some witty remark"; 

(Geprüft VS)

8

ich Ihr Programm übernehmen verhält sich wie Standard-Unix-Tools , wenn eine Datei nicht angegeben wird, wird sie in die Standardausgabe geschrieben, und wenn eine Datei angegeben wird, wird sie in diese Datei geschrieben. Sie können umleiten, um in einen anderen Stream-Puffer zu schreiben. Solange Ihre Weiterleitung aktiv ist, wird alles, was an cout geschrieben wurde, transparent an das von Ihnen angegebene Ziel geschrieben. Sobald die Umleitung Objekt den Gültigkeitsbereich verlässt, wird der ursprüngliche Strom gesetzt und Ausgang wieder auf den Bildschirm schreiben:

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

Nun wird cout in die Datei umgeleitet, solange das Rohr in Haupt am Leben ist. Sie können es "produktionsfertig" machen, indem Sie es nicht kopierbar machen, da es nicht kopierbereit ist: Wenn die Kopie den Gültigkeitsbereich verlässt, wird der ursprüngliche Stream bereits wiederhergestellt.

+0

Ich denke, diese Struktur sollte ein Singleton sein. –

+2

Hosam, es ist absichtlich kein Singleton, um vorübergehend das Ziel von Cout zu ändern, würde ein Singleton cout für immer ändern. Auch wenn Sie es nicht nur vorübergehend ändern wollen, wenn Sie etwas ohne Singleton machen können, sollten Sie es ohne tun. Hier, ich denke, es kann ohne –

0

Das dauerte ungefähr zwei Stunden. Grundsätzlich habe ich eine externe Klasse, die eine Testsuite ausführt. Ich sende einen Delegaten ein, um die Tests zu starten. Um Zugriff auf die Ausgabe zu haben, muss ich einen Ausgabestream senden.Ich denke, ich hätte pro Test einen anderen Stream machen können. Wie auch immer, ich wollte den Offstream weitergeben, um später benutzt zu werden.

// 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; 
}; 
+0

klar gemacht werden Sind Sie sicher, dass Sie dies an der richtigen Stelle gesetzt haben? Es scheint nicht auf die Frage zu reagieren ... – dmckee