C++标准库:如何为cout,cerr,cin和endl编写包装器?

Ash*_*ppa 16 c++ iostream

我不喜欢using namespace std,但我也厌倦了键入std::在每一条战线cout,cin,cerrendl.所以,我想给他们这样简短的新名字:

// 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;
Run Code Online (Sandbox Code Playgroud)

这有效.但是,上面有什么问题我错过了吗?有没有更好的方法来实现同样的目标?

sbi*_*sbi 84

亚历克斯给了你一个如何在语法上解决这个问题的答案.但是,我想指出关于这个问题的另外两个论点:

  1. 无论你是使用using指令(using namespace std)还是其较小的邪恶妹妹,使用声明(using std::cout),重载都可能导致令人讨厌的惊喜.std::花半夜调试来找出你的代码std::distance()而不是你自己的distance()函数相比,输入并不是很麻烦,只是因为你犯了一个小错误而且std::distance()意外地是一个更好的匹配.

  2. 一行代码被写入一次,但是 - 根据其生命周期 - 它被读取数十,数百甚至数千次.因此,编写一行代码所花费的时间根本不重要,重要的只是读取和解释一行代码所花费的时间.即使用一个适当std::的位置写一条线需要花费三倍的时间,如果它的读取速度只提高了10%,那么它仍然值得一试.
    所以重要的问题是:是否更容易阅读和解释一系列代码,std::或者更难?从另一个答案:

    这里还有一个数据点:很多年前,我也常常发现它必须为标准库中的所有内容添加前缀std::.然后我在一个项目中工作,在开始时决定using禁止指令和声明,除了函数范围.你猜怎么着?我们大部分时间花了很长时间才习惯编写前缀,经过几个星期后,我们大多数人甚至同意它实际上使代码更具可读性.(这是有原因的:无论你喜欢更短或更长的散文都是主观的,但前缀客观上增加了代码的清晰度.不仅是编译器,而且你也发现更容易看到引用哪个标识符.)

    十年来,该项目增长了数百万行代码.由于这些讨论一次又一次地出现,我曾经很好奇这个(允许的)功能范围using实际上在项目中的使用频率.我找了它的来源,只发现了一两个地方使用它.对我而言,这表明,一旦尝试过,开发人员std::即使每100kLoC使用一次指令也不会感到痛苦,即使在允许使用它的情况下也是如此.

    我觉得很遗憾你会发现每本书和教程都会跳过std::,因为这会让人们习惯于以这种方式阅读代码.当我教C++几年(在上述经历之后)时,我告诉我的学生我不想using在他们的代码中看到任何指令或声明.(该规则的唯一例外是using std::swap,BTW,你需要在swap(a,b)命名空间之外获取重载std.)一旦他们习惯了,他们就不介意了,当被问及时,他们说他们找到没有std::前缀混乱的代码.有些人甚至在std::他们从没有它的书或教程中输入的代码中添加了前缀.

一句话:键入的内容std::是如此之难以致每个人都如此努力?到现在为止,我已经做了超过15年,我完全不会错过using.

  • @There:你可能已经意识到你对大卫的最后两条评论在我标记为冒犯之后就消失了.这不是我第一次看到这件事发生在你身上.现在,我将停止与您进行讨论.我学会了尊重大卫的见解,我喜欢和他讨论,因为我从中学到了很多东西.你,OTOH,并没有讨论获得新的见解,你只是在讨论证明自己的观点,因此如果讨论不顺利,你会生气.我可以做得很好,而不会浪费我的时间.祝你今天愉快. (9认同)
  • +1(我希望我能做得更多)因为"一行代码会被写入一次,但是 - 根据其生命周期,它会被读取数十,数百甚至数千次.所以写一行所需的时间代码根本不重要,重要的只是读取一行和解释代码所花费的时间." - 如此真实,但很难让同事相信这一点. (5认同)
  • Sbi:我不得不承认我早期受到书籍或其他使用"使用"来源的代码的影响.我可能受到Java和Python中类似指令的影响.在思考了你的推理(并且没有找到更好的选择)之后,我决定修改代码以使用std :: all到处.感谢您抽出时间详细回复:-) (4认同)
  • @There我们无能为力:`auto`不是为了减少输入,而是为了创建你不能拼写名字的类型的变量.只是你可以使用它来减少输入,但它添加的主要功能是能够写出:`auto lambda = [](int x){return x*x; 如果没有`auto`,这是不可能的. (4认同)
  • 哼,没有看到.我也确信前缀增加了清晰度,特别是当命名空间和子文件夹匹配时,以便您知道哪个包含了特定对象:) (3认同)
  • @sbi C++的一些(大多数)设计者认为输入std ::和其他命名空间可能不仅很难,而且会使代码难以阅读.这就是他们使用声明和使用指令"发明"的原因.我很抱歉,但是当有人问我每次使用标准库时输入五个字符很难,我就是无法忍受.在代码中,你所说的超过几百万行可能已经输入好几千个额外/剩余字符.输入它的时间可能是用来做更多有用的事情.为什么你现在认为他们使用汽车的新标准呢? (2认同)
  • 实际上,引入命名空间的全部原因是为了摆脱不必要的前缀.否则只需调用流`std_cin`,`std_cout`和`std_cerr`并为实现保留以`std_`开头的每个名称就可以了. (2认同)

Ale*_*lli 59

为什么不

using std::cin;
using std::cout;
Run Code Online (Sandbox Code Playgroud)

等等?然后在您的代码中,您可以使用cin,cout等等,而不会意外地将所有其余的std命名空间注入到您的代码中.

  • @Ashwin:`using namespace_name :: identifier`被称为"名称空间声明",而`using namespace_name`被称为"名称空间指令". (8认同)