2010-03-09 7 views
6

Wenn ich versuche, den CodeLesen von cin oder einer Datei

istream in; 
if (argc==1) 
     in=cin; 
else 
{ 
     ifstream ifn(argv[1]); 
     in=ifn; 
} 

gcc nicht zu kompilieren, beschweren, dass operator= privat ist. Gibt es eine Möglichkeit, eine istream auf unterschiedliche Werte basierend auf einer Bedingung festzulegen?

Antwort

4

Sie können ohne Bezugnahme auf cin des streambuf mit einem anderen, und in einigen Programmen ist dies einfacher als die allgemeine Strategie von rund vorbei iStreams ersetzen cin direkt.

int main(int argc, char* argv[]) { 
    ifstream input; 
    streambuf* orig_cin = 0; 
    if (argc >= 2) { 
    input.open(argv[1]); 
    if (!input) return 1; 
    orig_cin = cin.rdbuf(input.rdbuf()); 
    cin.tie(0); // tied to cout by default 
    } 

    try { 
    // normal program using cin 
    } 
    catch (...) { 
    if (orig_cin) cin.rdbuf(orig_cin); 
    throw; 
    } 

    return 0; 
} 

Auch wenn es extrem selten ist cin zu verwenden, nachdem die Steuerung verlässt Haupt, die oben try-catch vermeidet undefiniertes Verhalten, wenn das ist etwas, das Ihr Programm tun könnte.

+0

Warum ist es notwendig, cin an cout zu binden, nachdem es an die Datei gebunden wurde, aber nicht im catch-Block? – m42a

+0

@ m42a ist es _outied_ von cout. Aber ich stimme zu, dass wir es vielleicht zurückbinden wollen. –

+0

@ m42a: Das Binden wirkt sich auf das Flushing aus (bevor cin von stdin liest, leert es cout), was nicht notwendig ist, wenn cin hier "umgeleitet" wird. In den meisten Fällen wäre es ein logischer Fehler von cin zu lesen, nachdem control leaves main verlassen hat, aber zumindest wenn Sie den streambuf wiederherstellen, vermeiden Sie undefiniertes Verhalten (das Filebuf aus dem ifstream wird zerstört). Sie können 'cin.tie (& cout)' verwenden, wenn Sie möchten. –

4

Also, ist es nicht beschweren "kein geeigneter Konstruktor verfügbar"? Wie auch immer, Sie können es wie folgt ändern.

void Read(istream& is) 
{ 
    string line; 
    while (getline(is, line)) 
     cout << line; 
} 

int main(int argc, char* argv[]) 
{ 
    if (argc == 1) 
     Read(cin); 
    else 
    { 
     ifstream in("sample.txt"); 
     Read(in); 
    } 
} 
+2

Sie sollten erklären, warum Sie dies getan haben, nicht nur etwas Code posten. Stream-Objekte können nicht kopiert oder zugewiesen werden. In der Regel übergeben wir einen Stream als Nonconst-Referenz, weil wir ein IO-Objekt übergeben, das davon lesen oder schreiben möchte. –

+0

@Alexandros, wahr. Ich hätte das tun sollen. – Jagannath

5

Sie könnten einen Zeiger für in, zum Beispiel verwenden:

istream *in; 
ifstream ifn; 

if (argc==1) { 
    in=&cin; 
} else { 
    ifn.open(argv[1]); 
    in=&ifn; 
} 
1

Sie können solche Streams nicht beeinflussen. Was Sie erreichen möchten, können Sie jedoch mit einem Zeiger auf einen iStream erzielen.

#include <fstream> 
#include <istream> 
#include <iostream> 

using namespace std; 

int main(int argc, char *argv[]) 
{ 
    istream *in; 
    // Must be declared here for scope reasons 
    ifstream ifn; 

    // No argument, use cin 
    if (argc == 1) in = &cin; 
    // Argument given, open the file and use it 
    else { 
    ifn.open(argv[1]); 
    in = &ifn; 
    } 
    return 0; 

    // You can now use 'in' 
    // ... 
}