重载函数运算符

时间:2016-06-14 15:19:55

标签: c++ operator-overloading

记录器的一个问题是即使您不想要它们也会记录。它们通常要么硬连线写入文件,要么回显到控制台 - 有时两者都是。 这与单元测试相反,其中记录到任一接收器将减慢测试速度。

我也反对使用printf样式的可变参数,因为人们切割,粘贴和忘记更改参数类型或从字符串中删除参数时,它们总是会出错。

所以我决定对此采取一些措施。

我的基本想法是让一个LogStream对象接受ostream作为参数,这样你就可以在单元测试中指定一个文件,控制台或者静默地吞下它。这是通过 作为同时接受严重性级别的Logger类的参数。

这是记录器的概念流程,它只将致命事件记录到ostringstream(从单元测试中解释):

std::ostringstream oss;
auto logstream = LogStream(oss);
auto logger = Logger(logstream, FATAL);
logger(INFO) << "This is a log test\n"; // (1)
std::cout << oss.str();  // Display nothing as nothing fatal has been logged 

考虑到这个问题,我需要一个临时流(ostream可以工作)来保存流,然后再决定它是否满足要放在LogStream对象中的条件。

我遇到的问题是在第(1)行,您将拥有函数调用运算符,它返回对LogStream的引用,并在退出后构建其余的流:

LogStream& operator()(Severity severity)
{
    // stream not completed
    return *m_dest;
}

我认为有一种方法,因为你可以获得使插入运算符重载的朋友函数,它接受一个流参数:

std::ostream& operator<<(std::ostream& os, const Complex& c)
{
    os << c.real << '.' << c.imaginary;
    return os;
}

但到目前为止,我一直无法弄清楚函数运算符的确切语法。

是否可能,或者我是在咆哮错误的树?

1 个答案:

答案 0 :(得分:1)

你需要像这样的设计:

enum class LogLevel
{
    FATAL,
    INFO
};

class LogStream : public std::ostream
{
public:
    LogStream( const std::ostream& )
    // ...
    {
    }

};

class EatStream : public std::ostream
{
    // does nothing 
};

class Logger
{
    const LogStream m_logger;
    const EatStream m_nolog;
    const LogLevel  m_loglevel;
public:
    Logger( const LogStream&&, const LogLevel ) // I'd suggest move, but you might as well just take a reference and copy
    // ...
    {
        // ...
    }

    std::ostream& operator()( const LogLevel level )
    {
        return  level <= m_loglevel ? m_logger : m_nolog;
    }
};

这里的关键是LogStream和EatStream有一个共同的基础,你的operator()通过引用返回。它不一定是std :: ostream,因为方便或者懒惰才使用它。一旦返回对公共库的引用,就可以正确地从vftable调用虚拟。请注意,您返回的引用由Logger保持活动状态,因此它不应超出operator()()的结果范围(在您的情况下这可能不是问题,只是为了完整性而注明)。