Zuweisen eines Variablennamens Cout
Frage
Wie kann ich in ANSI C ++ dem Cout -Stream einem variablen Namen zuweisen? Ich möchte, wenn der Benutzer einen Ausgabedateinamen angegeben hat, sende ich dort aus der Ausgabe. Andernfalls sende ich ihn auf den Bildschirm. 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 dies auch als Makrofunktion versucht:
#define OUTPUT outFileRequested?outFile:cout
OUTPUT << "whatever" << endl;
Aber das gab mir auch einen Compiler -Fehler.
Ich nahm an, ich könnte entweder einen wenn-dann-Block für jede Ausgabe verwenden, aber ich möchte das vermeiden, wenn ich könnte. Irgendwelche Ideen?
Lösung
Verwenden Sie eine Referenz. Beachten Sie, dass die Referenz vom Typ sein muss std::ostream
, nicht std::ofstream
, seit std::cout
ist ein std::ostream
, Sie müssen also den am wenigsten gebräuchlichen Nenner verwenden.
std::ofstream realOutFile;
if(outFileRequested)
realOutFile.open("foo.txt", std::ios::out);
std::ostream & outFile = (outFileRequested ? realOutFile : std::cout);
Andere Tipps
Ich gehe davon aus, dass sich Ihr Programm wie Standard -UNIX -Tools verhält, wenn keine Datei an die Standardausgabe geschrieben wird und wenn eine Datei in diese Datei geschrieben wird. Sie können umleiten cout
in einen anderen Stream -Puffer schreiben. Solange Ihre Umleitung lebt, wird alles, was auf Cout geschrieben wurde, transparent an das von Ihnen festgelegte Ziel geschrieben. Sobald das Umleitungsobjekt aus dem Umfang ausgeht, wird der ursprüngliche Stream ausgegeben und die Ausgabe wird erneut 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 Pfeife im Main lebt. Sie können es "Produktion bereit" machen, indem Sie es nicht schöpferbar machen, da es nicht bereit ist, kopiert zu werden: Wenn die Kopie aus dem Umfang ausgeht, wird der ursprüngliche Stream bereits wiederhergestellt.
Sie finden eine sehr detaillierte Erklärung, wie dies hier zu tun ist:http://groups.google.com/group/comp.lang.c++/msg/1d941c0f26ea0d81?pli=1
Hoffentlich schreibt jemand dies klarer auf, damit Stack Overflow die Punkte nimmt ...
Folgen Adam Rosenfield's Tracks, aber das Problem der Referenzinitialisierung mit ternären und Comma -Operatoren 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)
Ich denke, Adam ist 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 könnten dann einen Verweis als den Wert des Zeigers definieren, aber er wäre nicht global
std::ostream & outFile = *poutFile;
Ich bin mir nicht sicher, ob Sie eine Variable von Stream Cout zuweisen können. Cout ist ein Objekt vom Typ ostream (während CIN vom Typ iStream ist) und ich bin mir nicht sicher, ob einer von der anderen erbt. Vielleicht ist etwas, das überprüft wird, ob eine Datei angegeben/existiert, und das Erstellen des entsprechenden Stream -Typs wäre ein besserer Ansatz.
Dies dauerte ungefähr zwei Stunden. Grundsätzlich habe ich eine externe Klasse, die eine Testsuite ausführt. Ich sende einen Delegierten ein, um die Tests auszuführen. Um Zugriff auf die Ausgabe zu haben, muss ich einen Ausgabestream senden. Ich glaube, ich hätte einen anderen Strom pro Test machen können. Wie auch immer, ich wollte im Ofstream weitergeben, um später verwendet 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;
};