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)

rubenvb
  • 74,642
  • 33
  • 187
  • 332
  • Why do you want it to be `static`? – Matteo Italia Feb 22 '11 at 17:51
  • 1
    What is the type of Output::m_stream? – Harper Shelby Feb 22 '11 at 17:52
  • 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. – rubenvb Feb 22 '11 at 17:55
  • @Harper: that's part of the question `:s` – rubenvb Feb 22 '11 at 17:57
  • 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 &`. – Matteo Italia Feb 22 '11 at 17:57
  • @%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`... – rubenvb Feb 22 '11 at 18:13

3 Answers3

10
struct Output
{
    static ostream& stream;
};

ostream& Output::stream = cout;

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

Works fine here.

Stefan Monov
  • 11,332
  • 10
  • 63
  • 120
  • 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. – rubenvb Feb 22 '11 at 18:03
  • @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? – davka Feb 22 '11 at 18:24
  • 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? – rubenvb Feb 22 '11 at 18:36
  • 1
    @rubenvb: [You can't reseat references](http://www.parashift.com/c++-faq-lite/references.html#faq-8.5). 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. – Stefan Monov Feb 22 '11 at 18:37
  • And they didn't want to introduce random new syntax such as `reseat_reference(anotherObj);` – Stefan Monov Feb 22 '11 at 18:44
  • 2
    @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". – Steve Jessop Feb 22 '11 at 18:45
  • 1
    ... 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. – Steve Jessop Feb 22 '11 at 18:49
  • 1
    @Steve Jessop: References weren't actually conceived as an alternative name for an object. [They were just necessary for operator overloading](http://stackoverflow.com/q/4716426). 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. – Stefan Monov Feb 22 '11 at 18:55
  • 1
    @Stefan: interesting, so "references are alternative names" is a post-hoc rationalization of the semantics that references needed to have for other reasons. Thanks! – Steve Jessop Feb 22 '11 at 19:24
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.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • 2
    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. – Martin York Feb 22 '11 at 17:58
  • Sometimes the compiler will squawk in this case. However, the OP is asking for a static reference which won't be copied. – Matt K Feb 22 '11 at 17:58
  • Yes. The emphasis is on wrapped and not RAW. – Martin York Feb 22 '11 at 19:10
  • 1
    It is like using a smart pointer where a plain pointer would suffice. Such an attitude leads to bloatware. Just use Java already, lol. – Maxim Egorushkin Feb 23 '11 at 10:12
5

You should store a std::ostream &.

tibur
  • 11,531
  • 2
  • 37
  • 39