【问题标题】:Default "NULL" value for an ofstreamofstream 的默认“NULL”值
【发布时间】:2020-12-25 00:17:07
【问题描述】:

我目前有一个函数

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;
}

具有类似于&amp;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?

【问题讨论】:

  • 创建一个抽象的 Logger 类。在一种实现中,您可以写入 ofs,而在另一种实现中,您可以执行其他操作。通过引用将记录器传入 myfun()。
  • @schteppe - 这需要复制myfun吗?我的意思是修改myfun,应该避免在两个不同的地方这样做。
  • 不,myfun 的实现将保持不变。我现在已经在答案中发布了伪代码。
  • 你可以使用一个很容易实现的no-op ostream。 stackoverflow.com/questions/11826554/…

标签: c++ null ofstream


【解决方案1】:

我希望使用 myfun 的应用程序无需修改也能正常工作。

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

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

    // ...
}

您不能对此类函数使用引用参数ofstream&amp; ofs,因为引用不能为空。

【讨论】:

  • 简单的解决方案!详细信息:在myfun 内应使用(*ofs),例如(*ofs) &lt;&lt; ...;。
  • 那是注释代码,但肯定应该是(*ofs)。顺便说一句,您也可以通过 if(!ofs) 删除 nullptr 比较
  • 这是我最终使用的。
【解决方案2】:

创建一个抽象的 Logger 类。它有一个记录消息的方法。在派生类中,您可以将日志记录添加到文件(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;
}

【讨论】:

  • 好。您应该为logger 添加默认值。如 OP 中所述,我希望使用 myfun 的应用程序仍然可以不加修改地工作。所以myfun(10) 应该仍然可以工作。
  • @sancho.sReinstateMonicaCellio 我必须做一些研究以确保它首先有效。将可变引用作为默认参数传递似乎有点问题:stackoverflow.com/questions/2816293/…
  • @sancho.sReinstateMonicaCellio myfun(10) 现在可以使用了。请参阅我的答案中的更新代码。
【解决方案3】:

在 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
}

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

【讨论】:

  • 如 OP 中所述,我希望使用 myfun 的应用程序仍然可以不加修改地工作。所以myfun(10) 应该仍然可以工作。
猜你喜欢
  • 1970-01-01
  • 2012-01-18
  • 2018-11-17
  • 2014-09-01
  • 1970-01-01
  • 2011-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多