是否有空流?可选打印

is there a null stream? optional printing

提问人:ZKlack 提问时间:10/4/2022 更新时间:10/4/2022 访问量:378

问:

我使用像这样的函数

void doStuff(type thing, bool print = false, std::ostream& S = std::cout)
{
    thing++;
    if(print)
        S << "new thing: " << thing << '\n';
}

这样我就可以使用相同的函数并决定调用是否希望它打印正在发生的事情的文档,以及如果我希望我可以在单独的流上打印它 - 我不知道我是否可以用 std::ostream 做到这一点-

我现在相信这样做会更好

void doStuff(type thing, std::ostream& S = NULL)
{
    thing++;
    if(S)
        S << "new thing: " << thing << '\n';
}

但这不起作用,因为 std::ostream 不接受 NULL

问题:
- 是否有某种流类型的常量停止 if 条件?
- 我是否可以使用更灵活地接受字符串流和文件流等流的不同类型的流?
-有没有更好的方法来处理灵活的文档?

C++ 输出

评论

2赞 πάντα ῥεῖ 10/4/2022
只需创建自己的实现,最终什么也做不了。这并不难。std::ostream
0赞 Quimby 10/4/2022
你可以用指针吗?
3赞 Some programmer dude 10/4/2022
为什么不使用重载来让一个实现使用流(并将其作为参数)和另一个不使用任何流(并且不将其作为参数)的实现?如果区别只是最后的打印,那么流打印函数可以对普通的东西调用非打印函数,然后打印结果。
1赞 πάντα ῥεῖ 10/4/2022
或多或少,这就是每个体面的日志记录框架在类别方面所支持的。
1赞 perivesta 10/4/2022
你也可以把一个作为参数std::optional<std::reference_wrapper<std::ostream>>

答:

0赞 Jude Davis 10/4/2022 #1

不要使用 ofstream 引用,而是使用指针,以便可以接受 .无法传递 NULL 的原因是引用无法引用,因为它可能会导致危险的未定义行为,如核心转储、段错误、磁盘重新格式化等。nullptrNULL

执行以下操作:

void doStuff(type thing, std::ostream* S = nullptr)
{
    thing++;
    if(S != nullptr)
        (*S) << "new thing: " << thing << '\n';
}

这样更安全一些,可以接受 .nullptr

总的来说,如果您只是输出到文件或控制台,ofstream 似乎是您的最佳选择。在灵活的文档方面,我这样做真的没有问题。我可能只有一个日志记录类,并用它来执行警告、信息日志、保存到文件等。

评论

2赞 πάντα ῥεῖ 10/4/2022
在较大的代码库中,这往往会变得乏味。我更喜欢包装接口,这样任何客户端代码都不需要知道或关心。std::ostream
5赞 francesco 10/4/2022 #2

可以使用 boost::iostream 库的 Null 接收器

下面是一个工作示例:

#include <iostream>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/null.hpp>

boost::iostreams::stream<boost::iostreams::null_sink> nullstream{boost::iostreams::null_sink()};

void print_to_stream(std::ostream& s = nullstream)
{
  s << "hello" << std::endl;
}

int main()
{
  std::cout << "calling print_to_stream with s = std::cout" << std::endl;
  print_to_stream(std::cout);
  std::cout << "calling print_to_stream without argument" << std::endl;
  print_to_stream();

  return 0;
}

您可能希望将变量隐藏在某些命名空间或类中。nullstream

评论

0赞 francesco 10/5/2022
嗨,@ZKlack,如果这个或其他答案适合您的问题,您可以考虑接受它。没有这方面的义务。
0赞 ZKlack 10/10/2022
谢谢,我是这个网站的新手,你的回答正是我想做的,也是最合适的。当我有时间再次感谢时,我会阅读有关提升库的信息:)<3
3赞 A M 10/4/2022 #3

编写自己的流并不难,可以在好书中找到。

我为您创建了一个“NULL”流类。

请看下面非常简单的例子。

#include <iostream>

// This is a stream which does not output anything
class NullStream : public std::ostream
{
    // streambuffer doing nothing
    class NullBuffer : public std::streambuf
    {
    public:
        int overflow(int c) noexcept override { return c; }
    } nullBuffer;

public:
#pragma warning(suppress: 26455)
    NullStream() : std::ostream(&nullBuffer) {}
    NullStream(const NullStream&) = delete;
    NullStream& operator=(const NullStream&) = delete;
};


// Define a global null stream
NullStream nout;

void doStuff(int& i, std::ostream& stream = nout)
{
    i++;
    stream << i << '\n';
}

int main() {

    int i{};
    doStuff(i, std::cout);
    doStuff(i, std::cout);
    doStuff(i, std::cout);
    doStuff(i);
    doStuff(i);
    doStuff(i);
    doStuff(i, std::cout);
}
1赞 Some programmer dude 10/4/2022 #4

正如我在评论中提到的,一个可能的解决方案可能是使用简单的函数重载。

// Function for not printing anything
void doStuff(type& thing)
{
    thing++;
}

// Function for printing things
void doStuff(type thing, std::ostream& S)
{
    // Do the common things first
    doStuff(thing);

    // And then print
    S << "new thing: " << thing << '\n';
}