Redirection of Streams

G

Gaijinco

I used C for a long time where I could open a file for input but if the
file didn't existed, then I redirected the input to the standard input,
something like:

FILE *id=fopen("data.in","r");

if(!id)
id=stdin;

I have read about streams but I haven't found how to do it, I suppose
it must look like:


fstream id("data.in",ios::in)

if(!id)
// what must be written here so id stream is "connected" to cin?
 
J

JH Trauntvein

Gaijinco said:
I used C for a long time where I could open a file for input but if the
file didn't existed, then I redirected the input to the standard input,
something like:

FILE *id=fopen("data.in","r");

if(!id)
id=stdin;

I have read about streams but I haven't found how to do it, I suppose
it must look like:


fstream id("data.in",ios::in)

if(!id)
// what must be written here so id stream is "connected" to cin?

You could actually do this by using pointers to stream objects as in
the following:

std::istream *in = new std::ifstream("data.in");
if(!(*in))
in = &std::cin;
 
B

Ben Pope

JH said:
You could actually do this by using pointers to stream objects as in
the following:

std::istream *in = new std::ifstream("data.in");
if(!(*in))
in = &std::cin;

Or, preferably, references to streams.

Ben Pope
 
K

Kai-Uwe Bux

Ben said:
Or, preferably, references to streams.

How would you go about this particular problem using references instead of
pointers. The whole point of using a pointer to a stream rather than a
stream was to be able to make it point to a different stream depending on
the outcome of some test. With a reference, that won't fly: you cannot
reseat a reference.


Best

Kai-Uwe Bux
 
M

Milan Cvetkovic

Kai-Uwe Bux said:
Ben Pope wrote:




How would you go about this particular problem using references instead of
pointers. The whole point of using a pointer to a stream rather than a
stream was to be able to make it point to a different stream depending on
the outcome of some test. With a reference, that won't fly: you cannot
reseat a reference.


Best

Kai-Uwe Bux

std::istream& is = std::cin;
std::ifstream ifs ("data.in");
if (ifs) is = ifs;
// use is after this.
 
B

Ben Pope

Kai-Uwe Bux said:
How would you go about this particular problem using references instead of
pointers. The whole point of using a pointer to a stream rather than a
stream was to be able to make it point to a different stream depending on
the outcome of some test. With a reference, that won't fly: you cannot
reseat a reference.


#include <iostream>
#include <fstream>

void doSomethingToOStream(std::eek:stream& os) {
os << "something";
}

int main() {
/* VC8 says the following needs a copy constructor,
* I'm not sure if that's correct; I've found a bug in
* VC8 that unnecessarily requires a copy constructor.
* I'm not sure if it applies here.
*
bool validFile = ofs;
std::eek:stream& os = validFile ? ofs : std::cout;
*/

// A solution is:
std::eek:fstream ofs("test");
if (ofs) {
doSomethingToOStream(ofs);
} else {
doSomethingToOStream(std::cout);
}
}

I don't think it's particularly outrageous to create a function that
operates on an istream to solve the problem though.

Ben Pope
 
B

Ben Pope

Milan said:
std::istream& is = std::cin;
std::ifstream ifs ("data.in");
if (ifs) is = ifs;
// use is after this.

You didn't compile that, did you?

Ben Pope
 
H

hermann.rodrigues

std::istream& is = std::cin;
Fixing this post:
std::ifstream ifs ("data.in");
if (ifs) ifs = std::cin;
// use ifs after this.
 
K

Kai-Uwe Bux

Fixing this post:
std::ifstream ifs ("data.in");
if (ifs) ifs = std::cin;
// use ifs after this.

And exactly how would that be a fix? You might get:

no match for 'operator=' in 'ifs = std::cin'


Best

Kai-Uwe Bux
 
K

Kai-Uwe Bux

Ben said:
#include <iostream>
#include <fstream>

void doSomethingToOStream(std::eek:stream& os) {
os << "something";
}

int main() {
/* VC8 says the following needs a copy constructor,
* I'm not sure if that's correct; I've found a bug in
* VC8 that unnecessarily requires a copy constructor.
* I'm not sure if it applies here.
*
bool validFile = ofs;
std::eek:stream& os = validFile ? ofs : std::cout;
*/

// A solution is:
std::eek:fstream ofs("test");
if (ofs) {
doSomethingToOStream(ofs);
} else {
doSomethingToOStream(std::cout);
}

I would call that a work around :)
}

I don't think it's particularly outrageous to create a function that
operates on an istream to solve the problem though.

I tried

bool validFile = ofs;
std::eek:stream& os = validFile ? ofs : std::cout;

and it works. I also think, it is required to work. However, this only works
once. Using a pointer, you can redirect the stream multiple times.

Maybe, one should have a little wrapper class around a stream pointer. That
way, one could have stream objects that support assignment. (I am thinking
of something like a reference count based pointer and the last guy closes
the stream).


Best

Kai-Uwe Bux
 
B

Ben Pope

Kai-Uwe Bux said:
I would call that a work around :)

Fair enough :)
I tried

bool validFile = ofs;
std::eek:stream& os = validFile ? ofs : std::cout;

and it works. I also think, it is required to work.

Yeah, this looks a lot like a bug I found in VC8. I had code that had
(publicly) inherited from a stringstream, but provided a proper copy
constructor that initialised the stringstream base in the initialiser
list. Throwing this object gave me the same error: cannot access
private member in compiler generated function (copy constructor of
stringstream).

I've informed MS.
However, this only works
once. Using a pointer, you can redirect the stream multiple times.

Understood. That's why the function call is just neater all round.
Maybe, one should have a little wrapper class around a stream pointer. That
way, one could have stream objects that support assignment. (I am thinking
of something like a reference count based pointer and the last guy closes
the stream).

Sounds neat as well, thanks for your insight.

Ben Pope
 
K

Kai-Uwe Bux

Ben said:
Yeah, this looks a lot like a bug I found in VC8. I had code that had
(publicly) inherited from a stringstream, but provided a proper copy
constructor that initialised the stringstream base in the initialiser
list. Throwing this object gave me the same error: cannot access
private member in compiler generated function (copy constructor of
stringstream).

Hm, that is a little different. I think

std:eek:stream& os = validFile ? ofs : std::cout;

is required to work because it does *not* invoke any copy constructors. This
line is just initializing a reference from an lvalue [5.16/4] -- I am
assuking here that ofs and std::cout have the same type.

However, something like

std::stringstream i_str = some_cond ? str_stream_1 : str_stream_2;

is an entirely different matter (note the absence of &). In this case, a
copy constructor is invoked which for streams, I think, is required to
fail.


Best

Kai-Uwe Bux
 
B

Ben Pope

Kai-Uwe Bux said:
Ben said:
Yeah, this looks a lot like a bug I found in VC8. I had code that had
(publicly) inherited from a stringstream, but provided a proper copy
constructor that initialised the stringstream base in the initialiser
list. Throwing this object gave me the same error: cannot access
private member in compiler generated function (copy constructor of
stringstream).

Hm, that is a little different. I think

std:eek:stream& os = validFile ? ofs : std::cout;

is required to work because it does *not* invoke any copy constructors. This
line is just initializing a reference from an lvalue [5.16/4] -- I am
assuking here that ofs and std::cout have the same type.

However, something like

std::stringstream i_str = some_cond ? str_stream_1 : str_stream_2;

is an entirely different matter (note the absence of &). In this case, a
copy constructor is invoked which for streams, I think, is required to
fail.

I understand that. Consider:

#include <sstream>
#include <iostream>

class fail : public std::stringstream {
public:
fail() : std::stringstream() {}
fail(const fail& rhs) : std::stringstream(std::ios::in |
std::ios::eek:ut) {}
};

int main() {
try {
throw fail();
} catch(fail& e) {
}
}

I have provided a perfectly acceptable, although, admittedly not great,
copy constructor, yet VC8 fails compilation with the following error:

C:\Program Files\Microsoft Visual Studio 8\VC\include\sstream(513) :
error C2248: 'std::basic_ios<_Elem,_Traits>::basic_ios' : cannot access
private member declared in class 'std::basic_ios<_Elem,_Traits>'
with
[
_Elem=char,
_Traits=std::char_traits<char>
]
C:\Program Files\Microsoft Visual Studio 8\VC\include\ios(151)
: see declaration of 'std::basic_ios<_Elem,_Traits>::basic_ios'
with
[
_Elem=char,
_Traits=std::char_traits<char>
]
This diagnostic occurred in the compiler generated function
'std::basic_stringstream<_Elem,_Traits,_Alloc>::basic_stringstream(const
std::basic_stringstream<_Elem,_Traits,_Alloc> &)'
with
[
_Elem=char,
_Traits=std::char_traits<char>,
_Alloc=std::allocator<char>
]

<snip similar errors cascaded into istream and ostream>

It has attempted to create a copy constructor for the stringstream base,
even though one is not required (I have provided a copy constructor for
fail, that does not require a copy constructor for the base).

This is the reason why I believe the previous compilation of:

std:eek:stream& os = validFile ? ofs : std::cout;

Also fails; for some reason it requires (and attempts to create) a copy
constructor of the stringstream, even though one is technically not
required.

Comeau online compiles it, and I'm pretty sure VC7.1 and GCC 4.x compile it.

Ben Pope
 
K

Kai-Uwe Bux

Ben said:
Kai-Uwe Bux wrote:
[snip]
However, something like

std::stringstream i_str = some_cond ? str_stream_1 : str_stream_2;

is an entirely different matter (note the absence of &). In this case, a
copy constructor is invoked which for streams, I think, is required to
fail.

I understand that. Consider:

#include <sstream>
#include <iostream>

class fail : public std::stringstream {
public:
fail() : std::stringstream() {}
fail(const fail& rhs) : std::stringstream(std::ios::in |
std::ios::eek:ut) {}
};

int main() {
try {
throw fail();
} catch(fail& e) {
}
}

I have provided a perfectly acceptable, although, admittedly not great,
copy constructor, yet VC8 fails compilation with the following error:

C:\Program Files\Microsoft Visual Studio 8\VC\include\sstream(513) :
error C2248: 'std::basic_ios<_Elem,_Traits>::basic_ios' : cannot access
private member declared in class 'std::basic_ios<_Elem,_Traits>'
with
[
_Elem=char,
_Traits=std::char_traits<char>
]
C:\Program Files\Microsoft Visual Studio 8\VC\include\ios(151)
: see declaration of 'std::basic_ios<_Elem,_Traits>::basic_ios'
with
[
_Elem=char,
_Traits=std::char_traits<char>
]
This diagnostic occurred in the compiler generated function
'std::basic_stringstream<_Elem,_Traits,_Alloc>::basic_stringstream(const
std::basic_stringstream<_Elem,_Traits,_Alloc> &)'
with
[
_Elem=char,
_Traits=std::char_traits<char>,
_Alloc=std::allocator<char>
]

<snip similar errors cascaded into istream and ostream>

It has attempted to create a copy constructor for the stringstream base,
even though one is not required (I have provided a copy constructor for
fail, that does not require a copy constructor for the base).

I see. You are right, that looks like a bug.

This is the reason why I believe the previous compilation of:

std:eek:stream& os = validFile ? ofs : std::cout;

Also fails; for some reason it requires (and attempts to create) a copy
constructor of the stringstream, even though one is technically not
required.

Comeau online compiles it, and I'm pretty sure VC7.1 and GCC 4.x compile
it.

I checked: g++-4.1.0 compiles it.


Best

Kai-Uwe Bux
 
M

Michiel.Salters

JH said:
....
You could actually do this by using pointers to stream objects as in
the following:

std::istream *in = new std::ifstream("data.in");
if(!(*in))
{
delete in; // Garbage collection is usually not enabled.
in = &std::cin;
}

HTH,
Michiel Salters
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top