11

Is there a way in C++ to check if an ostream object is cout or a ofstream object?

Something like:

ostream& output(ostream& out)
{
    if (out == cout)
        return out;
    else
    {
        out << "something different because its not going to the console" << endl;
        return out;
    }
}

The reason I want to do this, is that I want to overload the << operator to do two different things depending on what type of stream it is used with.

Is it possible to just overload the << operator twice each time with a different type of stream?

Updated to reflect intention better.

Jordan
  • 4,928
  • 4
  • 26
  • 39
  • Relevant: http://stackoverflow.com/questions/366955/obtain-a-stdostream-either-from-stdcout-or-stdofstreamfile/366969#366969 –  Jul 23 '10 at 13:57
  • 1
    What is your motivation for doing this? It seems like a really bad idea to me. – Brian Jul 23 '10 at 14:09
  • @Brian: I added above, that I want to use the `<<` operator to do two different things depending on the stream, alternative approaches are welcomed – Jordan Jul 23 '10 at 14:17
  • @Jordan: Yes, I know that you want to use the `<<` to do two different things depending on the stream. Why do you want to do this? It seems like a really bad idea to me. – Brian Jul 23 '10 at 14:29
  • 1
    The whole point of using streams is to make it anonymous for the destination so everything looks the same no matter what type stream you are using. What happens if somebody connects a file stream to file descriptor 2 (the standard out on most systems). This would be a totally different stream but to the OS it will be going to a console. Alternatively what if the OS hooked up the std::cout to a file, this is so far out of the application space that it would be undetectable inside the application. – Martin York Jul 23 '10 at 14:44
  • It sounds like your real question might be "how do I detect if output is to a terminal"? – Cascabel Jul 23 '10 at 14:48

4 Answers4

15

You will definitely get further by checking the streambuffer identity

if (s.rdbuf() == std::cout.rdbuf())

This is because it is trivially simple to cross-assign / alias streams to buffers, see http://www.cplusplus.com/reference/iostream/ios/rdbuf/ and the Josuttis book

sehe
  • 374,641
  • 47
  • 450
  • 633
  • So this is what I lightly termed 'aliasing' a stream buffer. I guess that wasn't too clear, so I have edited my comments to be clearer. – sehe Mar 14 '11 at 12:33
6

It sounds like what you really want to know is not whether the stream is cout but whether the underlying file descriptor is attached to a terminal? If that is so, you need the underlying file descriptor. Unfortunately, you can't get that from a iostream. If it's possible to use cstdio instead of iostream, then you can. If you do have the file descriptor, determining if you are writing to a terminal is a simple as seeing if tcgetattr() returns -1.

Also, don't let anyone tell you not do implement some functionality that you need because it tarnishes the purity of some leaky abstraction. If you really need different behavior, then do what you need to do to produce that functionality.

frankc
  • 11,290
  • 4
  • 32
  • 49
4

It's possible by checking the stream's 'identity': if ( &out == &cout ) ....

However, I'm in doubt on the usefullness of this test. If your function can handle any output stream, why bother about what stream it is using?

xtofl
  • 40,723
  • 12
  • 105
  • 192
  • 13
    Why? Maybe, to write one thing to a file and a different thing to a terminal. E.g., use escape sequences to colorize output when writing to a terminal. Though it won't work if STDOUT is redirected. – atzz Jul 23 '10 at 14:21
  • Thats unlikely to work all the time. You should cast objects to the same type before taking their address (In this case some form of common base stream type). – Martin York Jul 23 '10 at 14:39
  • @Martin York: is that the case for single-inheritance trees, too? – xtofl Jul 23 '10 at 14:52
  • @sehe: I didn't know that. What can you do in that case? – xtofl Mar 14 '11 at 08:51
  • @sehe: btw, what _is_ an aliased stream buffer? (cfr http://stackoverflow.com/questions/5296484/what-are-aliased-stream-buffers) – xtofl Mar 14 '11 at 09:45
  • I meant rdbuf() sharing/aliasing: see my own earlier answer http://stackoverflow.com/questions/3318714/check-if-ostream-object-is-cout-or-ofstream-c/5293107#5293107 – sehe Mar 14 '11 at 12:34
1

I consider changing how you stream based on the object you are streaming to do be a horrible idea that completely ignores the whole point of how the stream objects are intended to work. So, I would create a member class or function which returns an object of a type that handles the stream differently. So, for example, if you wanted to provide a colorized stream, you would call:

std::cout << myclass.colorstreamer << endl;

Edit:

Your proposal for handling streams is a bad idea because you have no clue how other people are going to use your code. It is completely unintuitive for a stream to behave differently depending on what object is doing the streaming. I liken this to having a function which returns a different result depending on who called it rather than dependent on what its arguments are, though I acknowledge that technically the stream is an argument.

As for how to do it this way, one way would be to create a colorstreamer, make this new class a member of myclass and make myclass a member of colorstreamer, then make colorstreamer's stream operator a friend of myclass. I'm more worried about the semantics of calling the function (i.e. using .colorstreamer to control how it streams rather than using the stream itself) than I am about how to implement it. My suggestion for how to implement it is quite possibly a bad way to do it; my C++ is rusty.

Brian
  • 25,523
  • 18
  • 82
  • 173
  • Could you please elaborate a little more on why it is a bad idea and could you be more specific as to how to approach the problem your way? – Jordan Jul 23 '10 at 14:42
  • @Jordan: Edited to answer your questions, though I think Martin York's comment on your question (i.e. "The whole point of using streams...") is a better wording for why it is a bad idea. – Brian Jul 23 '10 at 14:58