【问题标题】:Avoid multiple function member call on an instance in C++避免在 C++ 中的实例上调用多个函数成员
【发布时间】:2015-08-17 15:52:56
【问题描述】:

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

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

如你所见,我想强制客户端使用这样的类:

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

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

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

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

【问题讨论】:

  • 你不能,这些代码或多或少是等价的,除了你想要的表单在一个临时实例上工作。为什么要强制这样做呢?对我来说听起来像是一个 XY 问题。
  • 既然你的debug()info()等函数不是const,那不是已经禁止从临时调用它们了吗?那东西能编译吗?
  • 是的,它当然可以编译 :)

标签: c++ logging static-assert


【解决方案1】:

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

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

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

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

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

【讨论】:

  • 好的,谢谢。不幸的是,这不能用我的编译器编译(gcc 版本 4.7.3):/
  • gcc 4.7.3 应该支持 c++11。您是否尝试过使用 -std=c++11 标志进行编译?
  • 是的,我总是使用这个标志(我确实使用 C++11 API)。对于我的 .hpp 中的这一行:std::ostringstream &amp;debug() &amp;&amp;; 我收到此错误:Logger.hpp:106: error: expected ';' at end of member declaration
  • 看起来有几个问题正在发生。首先,您的编译器太旧,无法支持这一点。 :( 我用 gcc 4.8.2 测试过,没有问题。其次,您将无法返回静态 std::ostringstream 成员。但您应该能够从成员中删除 static,升级到新版本的 gcc,一切顺利。
  • 好的,这并不容易。我正在使用 Buildroot 工具链进行交叉编译,所以我必须重新编译我所有的嵌入式操作系统。我将使用 gcc 4.8.x 进行编译,我会看到的。再次感谢:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
  • 2015-11-01
  • 1970-01-01
  • 2011-02-08
  • 1970-01-01
相关资源
最近更新 更多