offstream 的默认 "NULL" 值

Default "NULL" value for an ofstream

我目前有一个功能

int myfun(const int a) {
    ...
    return rval;
}

执行多项操作。

我的意思是根据我可以传递的一些参数来调整它是否写入有关其行为的调试信息。 在我想写那个信息的情况下,我也想传递 ofstream 来使用。 我希望使用 myfun 的应用程序无需修改即可继续工作。

所以我最好改成

int myfun(const int a, ofstream & ofs) {
    ...
    if (!(ofs == NULL)) {
        ofs << ...
    }
    ...
    if (!(ofs == NULL)) {
        ofs << ...
    }
    return rval;
}

默认值类似于 &ofs=NULL。我知道 NULL 不合适。

处理这个问题的合适方法是什么?

注1: 我可以传递带有输出文件名的可选参数,但这不太灵活。

注2: 我也可以改成

int myfun(const int a, const bool debug_info, ofstream & ofs) {
    ...
    if (debug_info) {
        ofs << ...
    }

默认值 debug_info=false。 我想这仍然需要如上所述的 ofs 默认值。

注3: Default ofstream class argument in function 中接受的答案建议不带 ofs 参数的重载。 在我的情况下,这可能行不通,因为我的意思是在“ofs=NULL”时不要写任何东西。

注释 4: This other answer 显然有效,但对我来说似乎有些做作,而且我不确定它是否提供与传递 ofs.

相同的所有功能

相关:

Is there a null std::ostream implementation in C++ or libraries?

I want applications that were using myfun to still work with no modifications.

如果是这样,使用默认的 ofs nullptr

int myfun(const int a, ofstream *ofs = nullptr)
{
    if (ofs != nullptr)
    {
        // (*ofs) << ... ;
    }

    // ...
}

您不能为此类函数使用引用参数 ofstream& ofs,因为引用不能为 null。

在 C++17 中有一个涉及 std::optional 的解决方案,但由于它需要默认的可构造类型,因此也必须使用 std::reference_wrapper

#include <fstream>
#include <optional>
#include <functional>

int myfun(const int a, std::optional<std::reference_wrapper<std::ofstream>> ofs)
{
    if (ofs) {
        ofs->get() << "...";
        return 1;
    }
    else{
        return 0;
    }
}
#include <iostream>
int main(){
    std::ofstream file;
    //Calling is quite nice.
    std::cout<<myfun(10,{file})<<'\n'; //Prints 1
    std::cout<<myfun(10,{})<<'\n'; //Prints 0
}

这个解决方案的缺点是,虽然惯用,但在某些情况下过于冗长且语法繁重。

制作一个抽象记录器class。它有一个记录消息的方法。在派生的 classes 中,您可以将日志记录添加到文件 (ofstream) 中,或者什么都不做。您可以使用任何记录器,myfun() 的实现保持不变。

#include <fstream>

class Logger {
public:
    virtual void log(const char*) = 0;
};

class NullLogger: public Logger {
public:
    void log(const char*) override {};
};

class FileLogger: public Logger {
public:
    FileLogger(std::ofstream& s): ofs(s){}
    void log(const char* msg) override {
        ofs << msg;
    }
private:
    std::ofstream& ofs;
};

static NullLogger defaultLogger;
int myfun(const int a, Logger& logger=defaultLogger)
{
    logger.log("hello");
    // ...
    logger.log("asdf");
}

int main(){
    std::ofstream ofs;
    FileLogger fileLogger(ofs);
    NullLogger nullLogger;
    myfun(10,fileLogger); // logs to file
    myfun(10,nullLogger); // logs nothing
    myfun(10); // also logs nothing
    return 0;
}