2011-06-05 84 views
21

可能重复空:
Implementing a no-op std::ostream独立于平台的/ dev/C++中

是否有任何流相当于NULL在C++?我想编写一个函数,如果用户希望有内部输出到某处发生在流,但如果没有,输出会进入一些假的地方

void data(std::stream & stream = fake_stream){ 
    stream << "DATA" ; 
} 

我希望能够选择做data()data(std::cout)

+2

您正在寻找某种“黑洞”流你可以写太多,但对数据什么都不做的?你可以派生出一个我想的,但是大多数人在尝试写入之前只检查流指针是否为NULL。 – 2011-06-05 04:13:30

+1

什么''但是如果不是'就意味着什么?你为什么不写伪码来澄清你的问题? – Nawaz 2011-06-05 04:22:41

+0

在:我不在乎它在哪里,只要它显示任何用户将检查的地方,如文件,或终端 – calccrypto 2011-06-05 04:55:53

回答

33

编辑:从@Johannes绍布两者 - litb的邮件here稍作修改:

template<typename Ch, typename Traits = std::char_traits<Ch> > 
struct basic_nullbuf : std::basic_streambuf<Ch, Traits> { 
    typedef std::basic_streambuf<Ch, Traits> base_type; 
    typedef typename base_type::int_type int_type; 
    typedef typename base_type::traits_type traits_type; 

    virtual int_type overflow(int_type c) { 
     return traits_type::not_eof(c); 
    } 
}; 

// convenient typedefs 
typedef basic_nullbuf<char> nullbuf; 
typedef basic_nullbuf<wchar_t> wnullbuf; 

// buffers and streams 
// in some .h 
extern std::ostream cnull; 
extern std::wostream wcnull; 

// in a concrete .cpp 
nullbuf null_obj; 
wnullbuf wnull_obj; 
std::ostream cnull(&null_obj); 
std::wostream wcnull(&wnull_obj); 

使用那些:

void data(std::ostream& stream = cnull){ 
    // whatever... 
} 

现在,这看起来很酷,但下面的方法更短,工作,因为如果一个空指针被提供给ostream构造函数,它会自动设置badbit和静默忽略任何写入:

// in .h 
extern std::ostream cnull; 
extern std::wostream wcnull; 

// in .cpp 
std::ostream cnull(0); 
std::wostream wcnull(0); 

标准保证这个工程,从27.6.2.2 [lib.ostream.cons] p1描述的ostream,需要一个指针streambuf构造函数开始:

影响:构造类basic_ostream的对象,通过调用basic_ios<charT,traits>::init(sb)将初始值分配给基类。

basic_ios相关功能,27.4.4.1 [lib.basic.ios.cons] p3

void init(basic_streambuf<charT,traits>* sb);
后置条件:此功能的后置条件如表89所示:

从表89的重要行:

rdstate() - goodbit如果sb不是空指针,否则为badbit。

如果badbit设置27.6.2.6 [lib.ostream.unformatted]下被描述,会发生什么:

每个无格式输出功能通过构建sentry类的对象开始执行。如果此对象在转换为bool类型的值时返回true,则该函数将尽力生成请求的输出。

这意味着,如果sentry是假的,它不会。这里是如何的sentry转换为bool,从27.6.2.3 [lib.ostream::sentry] p3 & p5采取:

3)如果任何准备完成后,os.good()trueok_ == true否则,ok_ == false

5)operator bool();
效果:退货ok_。

ok_bool类型的ostream::sentry成员。)


注意,这些报价仍然存在于C++ 11,只是在不同的地方。在此答案出现的顺序:

  • 27.6.2.2 [lib.ostream.cons] p1 =>27.7.3.2 [ostream.cons] p1
  • 27.4.4.1 [lib.basic.ios.cons] p3 =>27.5.5.2 [basic.ios.cons]
  • 表89 =>表128
  • 27.6.2.6 [lib.ostream.unformatted] =>27.7.3.7 [ostream.unformatted] p1
  • 27.6.2.3 [lib.ostream::sentry] p3 & p5 =>27.7.3.4 [ostream::sentry] p4 & p5
+0

感谢您的好回答。这两种方案的'os.good()'有区别吗?使用'std :: ostream os(nullptr)','assert(os)'会失败,而使用'std :: ostream os(&nullobj)','assert(os)'不会?我只是猜测。 – Hugues 2014-11-19 16:47:35

1

Linux文件/ dev/null是你正在寻找的黑洞。在Windows中有一个名为NUL的设备:我从来没有试图打开该文件,但我用它从命令行

+0

...你可以在不打开这些特殊文件的情况下做同样的事情。从技术上讲,你所需要做的就是在你的'''重载中接受参数,然后根本就不对它们做任何事情。 – 2011-06-05 05:48:29

+0

这是真的。但用户仍然必须首先创建流 – calccrypto 2011-06-05 06:02:00

+0

,我将如何使用它?'std :: ostream stream = NUL'和'std :: ostream stream = std :: ostream(NUL)'不作为参数工作 – calccrypto 2011-06-05 06:13:32

-1

你可以尝试ostream(NULL,false),第一个输入是目标输出,我不知道第二个输入是什么exaclty的意思,但在跟踪代码后,似乎只是因为ostream没有地方写信,所以调用operator <<只是被ostream忽略。我的意思是在第一次调用状态更改为坏之后,它总是忽略,因为流状态的输入数据,这样你就可以使用下面的代码:

void data(std::ostream & stream = ostream(NULL,false)){ 
    stream << "DATA" ; 
} 
+3

-1,这不起作用。临时只能绑定到'const T&'引用,但是不能写入常量流。我认为MSVC允许这个作为扩展,但... – Xeo 2011-06-05 06:35:10

+0

它的工作原理和编译使用VC++,但似乎有一些与GCC的问题。 – Ali1S232 2011-06-05 06:44:14