14 Stimmen

Zuweisung von cout an einen Variablennamen

Wie kann ich in ANSI C++ den cout-Stream einem Variablennamen zuweisen? Wenn der Benutzer einen Namen für die Ausgabedatei angegeben hat, soll die Ausgabe dorthin gesendet werden, andernfalls soll sie auf den Bildschirm ausgegeben werden. Also so etwas wie:

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;

Ich habe versucht, dies auch als Makrofunktion zu tun:

#define OUTPUT outFileRequested?outFile:cout

OUTPUT << "whatever" << endl;

Aber auch das führte zu einem Compilerfehler.

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

37voto

Adam Rosenfield Punkte 373807

Verwenden Sie eine Referenz. Beachten Sie, dass der Verweis vom Typ sein muss std::ostream , nicht std::ofstream da std::cout ist eine std::ostream Sie müssen also 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 Stimmen

Das ist eine sehr elegante Lösung. Danke!

8voto

Ich gehe davon aus, dass sich Ihr Programm wie die Standard-Unix-Tools verhält, d.h. wenn keine Datei angegeben wird, schreibt es in die Standardausgabe, und wenn eine Datei angegeben wird, schreibt es in diese Datei. Sie können umleiten cout um in einen anderen Stream-Puffer zu schreiben. Solange die Umleitung aktiv ist, wird alles, was in cout geschrieben wird, transparent an das von Ihnen angegebene Ziel geschrieben. Sobald das Umleitungsobjekt den Anwendungsbereich verlässt, wird der ursprüngliche Stream wieder auf den Bildschirm geschrieben:

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

Jetzt wird cout in die Datei umgeleitet, solange die Pipe in main aktiv ist. Man kann sie "produktionsfähiger" machen, indem man sie nicht kopierbar macht, weil sie nicht kopiert werden kann: Wenn die Kopie den Bereich verlässt, wird der ursprüngliche Stream bereits wiederhergestellt.

0 Stimmen

Ich denke, diese Struktur sollte ein Singleton sein.

2 Stimmen

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

3voto

Douglas Mayle Punkte 19645

Eine sehr ausführliche Erklärung, wie das geht, finden Sie hier: http://groups.google.com/group/comp.lang.c++/msg/1d941c0f26ea0d81?pli=1

Hoffentlich schreibt das jemand deutlicher für Stack Overflow auf, um die Punkte zu nehmen...

1voto

Ates Goral Punkte 132294

Unter Adam Rosenfeld Das Problem der Referenzinitialisierung mit ternären und Komma-Operatoren wurde jedoch behoben:

bool outFileRequested = false;

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

outFile << "some witty remark";

(Getestet in VS)

0voto

KenE Punkte 1795

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

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

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

Sie könnten dann einen Verweis definieren, der den Wert des Zeigers darstellt, aber er wäre nicht global

std::ostream & outFile = *poutFile;

0 Stimmen

Sie sollten immer Referenzen gegenüber Zeigern bevorzugen. Und es kann mit Referenzen gemacht werden. Siehe den korrigierten Code oben.

1 Stimmen

Sicher, Sie können nur keine globale Variable mit einem Verweis verwenden, weil Sie nicht in der Lage sind, den richtigen Wert zu initialisieren.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X