How can I store a reference to `std::cout` as a class member
Asked Answered
G

3

5

I'm using a class meant to be used like this:

Output() << "Hello.\n";

In its operator<< I explicitely use std::cout, but I'd like to have a static class member that resolves to `std::cout´ so I can do stuff like this:

copy(some_string_set.begin(), some_string_set.end(), ostream_iterator<string>(Output::m_stream, ", "));

or something similar (I can't fix the bottom line until I get the static data member fixed.

I even tried auto, but GCC threw a

error: 'std::cout' cannot appear in a constant-expression

at me. How can I do what I want? (the point is not having to use std::cout all through my code, but have all output go through the Output class)

Genie answered 22/2, 2011 at 17:47 Comment(6)
Why do you want it to be static?Telemotor
What is the type of Output::m_stream?Preciousprecipice
As my Output class will constantly have temporaries created (each time the first line of code is used), I don't want to initialize it every time, plus the fact that the second code line needs a static member.Genie
@Harper: that's part of the question :sGenie
This doesn't seem a very clean design to me... why don't you use a global instance of the object (exactly as cout, cin, ... are globals)? By the way, the type should be std::ostream &.Telemotor
@%atteo: I plan on adding coloring support and so forth in the output, with the possibility to divert to a log file etc. I could also add a level of output by adding an integer argument to the constructor etc. Designwise it should be identical to QDebug...Genie
S
10
struct Output
{
    static ostream& stream;
};

ostream& Output::stream = cout;

int main()
{
    Output::stream << "hey";
}

Works fine here.

Sabelle answered 22/2, 2011 at 17:53 Comment(9)
That was my plan, but my internal const pirate tried to make it const, which wasn't possible, and in retrospect, unwanted by my design... Thanks for pointing me to the obvious.Genie
@rubenvb: I don't see much reason for such class. It is statically hardcoded at the beginning of the program to cout and you can't change it. If you want it to be any other stream as you say, you need to recompile. So what's the use? It looks just as a synonym for cout the way it is here. What if in the future you will want to, say, read an output file name from configuration and than to set your output to it?Agitate
Why wouldn't I be able to set the reference differently? It's not const, so I don't see a reason reassigning the reference won't work?Genie
@rubenvb: You can't reseat references. That's how references work. Once you create a reference, it will always point to the same object. The reason they made C++ this way isn't clear, but one reason is that a reference is treated syntactically as the object it references, and therefore, a syntax like Foo& theRef = obj; theRef = anotherObj; should call the the operator=() of obj, rather than make theRef point to anotherObj.Sabelle
And they didn't want to introduce random new syntax such as reseat_reference<theRef>(anotherObj);Sabelle
@Stefan: "The reason they made C++ this way isn't clear" - I don't think it's that unclear. It's because a reference was conceived as an alternative name for an object, just a variable name is a name for an object. If I do int i = 23;, then the only way to make i refer to a different object is to shadow it in a smaller scope, although of course I can change the value of the object by assigning a new value. The same is true of a reference to an object, as is true of a variable name. Perhaps it's unclear why they're called "references", ISTR Stroustrup considered calling them "aliases".Amabil
... after that initial conception, any resemblance that C++ references may bear to C++ pointers, or to pointers in Java (ahem, sorry, to references in Java), or different kinds of references in any other language, is coincidental.Amabil
@Steve Jessop: References weren't actually conceived as an alternative name for an object. They were just necessary for operator overloading. As you see from the Stroustrup quote there, he would've used pointers for the purpose but they were syntactically inappropriate - so he basically created a "new sort of pointer", just with a different syntax. So the resemblance isn't a coincidence. BTW, I'm glad I just found that quote, because at the end he actually gives a justification for why references aren't reseatable.Sabelle
@Stefan: interesting, so "references are alternative names" is a post-hoc rationalization of the semantics that references needed to have for other reasons. Thanks!Amabil
E
10

Store it as std::ostream*.

Sometimes people store references as members. This is error prone because the reference can not be reassigned, which causes assignment operator to do the wrong thing.

Ewing answered 22/2, 2011 at 17:56 Comment(4)
True: But the other side of the coin is that pointers can be NULL. You can get around the reference being non-re-assignable by using the boost reference objects. In my opinion always prefer reference until the point where you have no choice (you need to re-assign). Also note: The assignment operators do not do the wrong thing (they will result in a compiler error). Which is what you want.Ensiform
Sometimes the compiler will squawk in this case. However, the OP is asking for a static reference which won't be copied.Quibbling
Yes. The emphasis is on wrapped and not RAW.Ensiform
It is like using a smart pointer where a plain pointer would suffice. Such an attitude leads to bloatware. Just use Java already, lol.Ewing
R
5

You should store a std::ostream &.

Rajab answered 22/2, 2011 at 17:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.