7

When I try to compile the code

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

gcc fails, complaining that operator= is private. Is there any way to set an istream to different values based on a condition?

m42a
  • 1,322
  • 2
  • 10
  • 14

4 Answers4

5

You could use a pointer for in, e.g.:

istream *in;
ifstream ifn;

if (argc==1) {
     in=&cin;
} else {
     ifn.open(argv[1]);
     in=&ifn;
}
dmcer
  • 8,116
  • 1
  • 35
  • 41
4

So, is it not complaining "no appropriate constructor available" ? Anyways, you can modify it as below.

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);
    }
}
Jagannath
  • 3,995
  • 26
  • 30
  • 2
    You should explain why you did this, not just post some code. Stream objects cannot be copied or assigned, so typically we pass a stream as a nonconst reference because we pass an IO object intending to read from it or write to it. – Alexandros Gezerlis Mar 09 '10 at 06:50
4

You can replace cin's streambuf with another, and in some programs this is simpler than the general strategy of passing around istreams without referring to cin directly.

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

Even though it's extremely rare to use cin after control leaves main, the above try-catch avoids undefined behavior if that's something your program might do.

  • Why is it necessary to tie cin to cout after binding it to the file but not in the catch block? – m42a Mar 09 '10 at 07:50
  • @m42a it is _untied_ from cout. But I agree we may want to tie it back. – Alex Jasmin Mar 09 '10 at 09:25
  • @m42a: Tying affects flushing (before cin reads from stdin, it flushes cout) which isn't required when cin is "redirected" here. In most cases, it would be a logic error to read from cin after control leaves main, but at least if you restore the streambuf you'll avoid undefined behavior (the filebuf from the ifstream will be destroyed). You can use `cin.tie(&cout)` if you want. –  Mar 09 '10 at 09:32
1

You cannot affect streams like this. What you want to achieve can be obtained using a pointer to an istream though.

#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'
  // ...
}
Gnurou
  • 7,923
  • 3
  • 22
  • 32