避免在 C++ 中对一个实例调用多个函数成员

Avoid multiple function member call on an instance in C++

我为我的程序编写了一个记录器 class,但我想强制客户端以特定方式使用我的 class。这是我的 Logger class:

#ifndef __LOGGER_HPP
#define __LOGGER_HPP

#include <Uncopyable.hpp>
#include <sstream>

enum LoggerLevel
{
    ERROR,
    WARNING,
    INFO,
    DEBUG,
    ALL
};

class Logger : private Uncopyable
{
    private:

        static LoggerLevel reportingLevel;
        static std::ostringstream os;
        static bool hide;
        static std::string file;

        LoggerLevel messageLevel;
        std::string className;

    public:

        static void setVerbosity(LoggerLevel level);
        static void setLogFile(const std::string &file);
        static void hideOutput();
        static bool outputHidden();
        static std::ostringstream &getStream();

        Logger(const std::string &className);
        ~Logger();
        std::ostringstream &debug();
        std::ostringstream &info();
        std::ostringstream &warning();
        std::ostringstream &error();
};

#endif // __LOGGER_HPP

实施:

#include <Logger.hpp>
#include <iostream>
#include <fstream>
#include <cstdio>
#include <ctime>

using namespace std;

LoggerLevel Logger::reportingLevel = LoggerLevel::ALL;
ostringstream Logger::os;
string Logger::file;
bool Logger::hide = false;

Logger::Logger(const string &className) :
    className(className)
{
    os.str("");
}

Logger::~Logger()
{
    os << endl;

    if (this->messageLevel <= reportingLevel)
    {
        if (!hide)
        {
            if (this->messageLevel == LoggerLevel::ERROR)
            {
                cerr << os.str() << flush;
            }
            else
            {
                cout << os.str() << flush;
            }
        }

        if (!file.empty())
        {
            time_t now = time(nullptr);
            string time(ctime(&now));
            ofstream log(file, ios::in | ios::app);
            log << time.substr(0, time.length() - 1) << " " << os.str() << flush;
            log.close();
        }
    }
}

void Logger::setVerbosity(LoggerLevel level)
{
    Logger::reportingLevel = level;
}

void Logger::setLogFile(const string &file)
{
    Logger::file = file;
}

void Logger::hideOutput()
{
    Logger::hide = true;
}

bool Logger::outputHidden()
{
    return hide;
}

ostringstream &Logger::getStream()
{
    return os;
}

ostringstream &Logger::debug()
{
    os << "[DEBUG] " << this->className << ": ";
    this->messageLevel = LoggerLevel::DEBUG;
    return os;
}

ostringstream &Logger::info()
{
    os << "[INFO] " << this->className << ": ";
    this->messageLevel = LoggerLevel::INFO;
    return os;
}

ostringstream &Logger::warning()
{
    os << "[WARNING] " << this->className << ": ";
    this->messageLevel = LoggerLevel::WARNING;
    return os;
}

ostringstream &Logger::error()
{
    os << "[ERROR] " << this->className << ": ";
    this->messageLevel = LoggerLevel::ERROR;
    return os;
}

如您所见,我想强制客户端像这样使用 class:

Logger("MyCLass").debug() << "This is a debug message.";

所以我想静态地避免这种使用:

Logger myLogger("MyClass");
myLogger.debug() << "This is a debug message.";
myLogger.info() << "This is an information.";

有什么解决办法吗? 谢谢。

是的,有一个解决方案,感谢 C++11。您想要对每个日志记录函数进行右值引用限定:

std::ostringstream &debug() &&;
// etc.

换句话说,函数声明末尾的 && 意味着 debug() 和朋友只能在临时 Logger 对象上调用:

Logger("MyClass").debug() << "foo"; // fine

Logger log("MyClass");
log.debug() << "bar"; // compile-time error!