C++ Standard Library: How to write wrappers for cout, cerr, cin and endl?
Asked Answered
P

2

18

I do not like using namespace std, but I am also tired of having to type std:: in front of every cout, cin, cerr and endl. So, I thought of giving them shorter new names like this:

// STLWrapper.h

#include <iostream>
#include <string>

extern std::ostream& Cout;
extern std::ostream& Cerr;
extern std::istream& Cin;
extern std::string&  Endl;

// STLWrapper.cpp

#include "STLWrapper.h"

std::ostream& Cout = std::cout;
std::ostream& Cerr = std::cerr;
std::istream& Cerr = std::cin;
std::string _EndlStr("\n");
std::string& Endl = _EndlStr;

This works. But, are there any problems in the above which I am missing? Is there a better way to achieve the same?

Pneumatics answered 21/5, 2010 at 4:24 Comment(3)
This is only OK if you are a one man company and nobody else will ever read the code. Shortcuts like this only serve to make the code obfuscated and is rarely a good idea for a team of developers.Perutz
Martin: Point noted. Yes, this may not be a good idea when code will be used with other people.Pneumatics
The std::string& Endl defined here has different functionality than std::endl which attempts to flush the buffer.Shushubert
S
60

Why not

using std::cin;
using std::cout;

and so on? Then in your code you can use cin, cout, and so on, without accidentally injecting all of the rest of the std namespace into your code.

Skinhead answered 21/5, 2010 at 4:26 Comment(4)
[hand to head] I was not even aware that "using" can be used with non-namespace entities! Thanks! :-)Pneumatics
@Ashwin: using namespace_name::identifier is called a "namespace declaration", whereas using namespace_name is called a "namespace directive".Votaw
Sbi: Thanks so much for that! I am now going back to the books to read all about "using".Pneumatics
@Ashwin: Once you're reading up using, it can also be used to bring a base class identifier into a derived class' scope, so that it is considered for overload resolution, or to make a private base's identifier accessible in a derived class' interface. However, I haven't really seen those in the wild.Votaw
V
84

Alex has given you an answer how to syntactically solve that problem. However, I want to point out two other arguments regarding this issue:

  1. No matter whether you're employing a using directive (using namespace std) or its lesser evil sister, a using declaration (using std::cout), overloading might lead to nasty surprises. It's not much hassle to type std:: compared to spending half a night debugging to find out your code called std::distance() instead of your own distance() function, just because you made a small mistake and std::distance() accidentally is a better match.

  2. A line of code gets written once, but - depending on its lifetime - it is read tens, hundreds, and some even thousands of times. So the time it takes to write a line of code simply doesn't matter at all, important is only the time it takes to read and interpret a line of code. Even if it takes three times as long to write a line with all the proper std:: in place, if it makes reading it only 10% faster, it is still worth the trouble.
    So the important question is: Is it easier to read and interpret a line of code with all the std:: in place or is it harder? From another answer:

    Here's one more data point: Many, many years ago, I also used to find it annoying having to prefix everything from the standard library with std::. Then I worked in a project where it was decided at the start that both using directives and declarations are banned except for function scopes. Guess what? It took most of us very few weeks to get to used to write the prefix and after a few more weeks most of us even agreed that it actually made the code more readable. (There's a reason for that: Whether you like shorter or longer prose is subjective, but the prefixes objectively add clarity to the code. Not only the compiler, but you, too, find it easier to see which identifier is referred to.)

    In a decade, that project grew to have several million lines of code. Since these discussions come up again and again, I once was curious how often the (allowed) function-scope using actually was used in the project. I grep'd the sources for it and only found one or two dozen places where it was used. To me this indicates that, once tried, developers didn't find std:: painful enough to employ using directives even once every 100kLoC even where it was allowed to be used.

    I think it's sad that every book and tutorial you'll find skips std::, because that makes people getting used to read the code that way. When I taught C++ for several years (after the above mentioned experience), I told my students that I don't want to see any using directive or declaration in their code. (The only exception to that rule is using std::swap, BTW, which you'll need in order to have swap(a,b) pick up overloads outside of namespace std.) Once they got used to it, they didn't mind and, when asked about it, they said they find code without the std:: prefix confusing. Some even added the std:: prefix to code they typed from a book or tutorial which didn't have it.

Bottom line: What's so hard about typing std:: that everybody gets so worked up about it? By now I have been doing it for >15 years, and I don't miss using at all.

Votaw answered 21/5, 2010 at 7:1 Comment(27)
Sbi: I have to admit that I was influenced early on by code from books or other sources that used "using". I might have been a bit influenced by similar directives in Java & Python. After pondering about your reasoning (and seeing no better alternative), I have decided to fix the code to use std:: all over the place. Thanks for taking the time on a detailed reply :-)Pneumatics
+1 (I wish I could do more) for "A line of code gets written once, but - depending on its lifetime, it is read tens, hundreds, and some even thousands of times. So the time it takes to write a line of code simply doesn't matter at all, important is only the time it takes to read a line and interpret of code." -- So True but so difficult to convince this to coworkers.Holds
+1 Great argument. Count me as another convert. I'm adding 'using' to my list of verboten mechanisms along with arrays, global variables, macros, if-then-elseif-elseif-elseif... monstrosities, etc.Ame
Hum, didn't see that. I am also convinced that prefixing adds clarity, especially when namespaces and subfolders match, so that you know which include brought that particular object :)Lorna
@Votaw Some (majority) of the designers of C++ thought that typing std:: and other namespaces, may be not only hard but can make code harder to read. That's why they "invented" using declaration and using directive. And I'm sorry but when someone asks me what's hard about typing five more chars everytime you use standard library I just can't stand it. In code as you're saying with over few million lines probably good few thousands of extra/surplus chars has been typed. Time to type it could be spend to do more useful things. And why do you think now in new standard they use auto?Spell
Namespace directives at function scope are really useful whenever you use boost or <functional>. I wholeheartedly agree with everything you say though.Incomprehensible
@Votaw continue I'm not saying that one never should use fully scoped name of a obj but with such a famous objs like cin, cout and cerr it is a bit overdoing.Spell
@There: "Whether you like shorter or longer prose is subjective, but the prefixes objectively add clarity to the code." There is nothing I could add.Votaw
@Alexandre: Using declarations at function scope was allowed in that project. Yet, it was used very little. OTOH, none of those placeholder stuff was ever used, so I guess you have a point.Votaw
@Votaw "the prefixes objectively add clarity to the code." - not according to Bjarne, me and tons of other people.Spell
@There: When it comes to code, the only really objective judge is the compiler and the compiler agrees with me which one is less ambiguous. BTW, Stroustrup did get some things wrong, even according to his own, later, judgment (just think of implicit conversion operators or the term "RAII") and I have indeed found myself disagreeing with him once in a while over the last decades. So I'm not impressed by his name (especially so when used without citation). OTOH, I wager that, out of the regulars in SO's c++ tag, considerably more rep will be in favor of my POV regarding this than against it.Votaw
@There is nothing we can do: auto is not there to reduce typing, but to create variables of types for which you cannot spell the name. It just happens that you can use it to reduce typing, but the main functionality that it adds is being able do write this: auto lambda = [](int x){ return x*x; };, that would not be possible to do without auto.Dupe
@Votaw I don't really care how many people from SO will agree with you on that and how many won't. This is not the point. The point is that by using std:: to cin, cout and cerr you making your code less readable. Every mentaly healty c++ programmer knows that cout etc are "almost forbidden" to be used as names within user code. And I'm not saying that Bjarne is always right or that he never makes mistakes but he has more experience than you on working on big/important projects so I take his words not yours where comes to good programming practice and style.Spell
sbi continue but, I repeat: I'm not saying that fully scoped names are bad or wrong. Yes they are necessary but in cases of such megastars like cout, cin and cerr definitely not (according to Bjarne, me and tons of others).Spell
@David no, you're wrong. auto is introduced not only for the (valid) reason you've described but also to remove unnecessary clatter from definitions like this: vector<vector<Map<int,set<char>>>> v;//initialize and get iterator i = v.begin(). And you are also wrong saying that auto isn't re-introduced to reduce typing. That's exactly one of the main reason why auto is re-introduced. Another reason for re-introducing this keyword is for situations when you cannot now in advance what type the variable will have.So yes, you are wrong. www.nuonsoft.com/blog/2009/06/08/auto-keyword-in-visual-c-2010/Spell
@There: That quote from Bjarne seems to support David's statement. As for making a fool - I've flagged your last two comments as offensive.Votaw
@Votaw go on Bjarne's web page check what does he has to say about auto and what for it was reinvented and then make a comment and decide what it seems Bjarne to have in mind not some David.Spell
@There: You might have realized that your last two comments towards David disappeared after I flagged them for being offensive. This is not the first time I've seen this happen to you. And it's the moment I will stop this discussion with you. I have learned to respect David's insights and I enjoy discussing with him, because I learn a lot from doing so. You, OTOH, are not discussing to gain new insights, you're just discussing to prove your point, and will therefore get angry if the discussion doesn't go your way. I can do very well without wasting my time on that. Have a nice day.Votaw
@Votaw I am not here to discuss things. It's not a discussion forum. When someone talks rubbish (like he did about auto) I just correct such person. And do I have to prove my point? Wait a sec, it's not my point it's Bjarne's point, you know. And after reading Bjarne's reasoning are you still convinced that what Bjarne says supports David's statement? David knew that there are bells ringing but wasn't sure in which church.Spell
@Votaw "The Design and Evolution of C++" 17.4.1 paragraph 5. And as I've said Bjarne has light years more of experience and knowledge about C++ than you so every reasonable person will follow his advice.Spell
so as i pointed out above, Bjärne is like Chuck Norris but with just a bit less hairReplete
@lurscher: I have no idea what you are referring to. (Nor do I know some Bjärne.)Votaw
Actually, the whole reason namespaces were introduced was to get rid of unneccesary prefixes. Otherwise simply calling the streams std_cin, std_cout and std_cerr and reserving every name starting with std_ for the implementation would have done the trick.Luttrell
I am just getting started in Visual C++ (experienced with C#) ...this is good information and I can see the harm in getting too comfortable with using and how horrible ambiguities can burrow themselves deep in your code. I'll take this advice to heart ... +1!!!Iceland
You have convinced me that using is best avoided. However, you have also convinced me that good c++ code is often ugly and obnoxious.Alphitomancy
@Zboson: Beauty is in the eye of the beholder. Clarity is objective.Votaw
@sbi, I guess this fixes a problem in C #26525276Alphitomancy
S
60

Why not

using std::cin;
using std::cout;

and so on? Then in your code you can use cin, cout, and so on, without accidentally injecting all of the rest of the std namespace into your code.

Skinhead answered 21/5, 2010 at 4:26 Comment(4)
[hand to head] I was not even aware that "using" can be used with non-namespace entities! Thanks! :-)Pneumatics
@Ashwin: using namespace_name::identifier is called a "namespace declaration", whereas using namespace_name is called a "namespace directive".Votaw
Sbi: Thanks so much for that! I am now going back to the books to read all about "using".Pneumatics
@Ashwin: Once you're reading up using, it can also be used to bring a base class identifier into a derived class' scope, so that it is considered for overload resolution, or to make a private base's identifier accessible in a derived class' interface. However, I haven't really seen those in the wild.Votaw

© 2022 - 2024 — McMap. All rights reserved.