重载 C 预处理器宏 - 基于调用语法的判别

Overloading C Preprocessor Macros - Discimination Based on Call Syntax

我目前正在开发一个 cpp 记录器,旨在在每条打印消息之前显示 __FILE____LINE__。就我而言,我们主要使用 2 种打印方法:printf 风格和 std::cout 风格。目前我有每种风格的宏:

#define HATFormatFatal(...)    HATLogger::logFormat(HATLogger::LogLevel::FATAL, __FILE__, __LINE__, __VA_ARGS__)
#define HATFormatError(...)    HATLogger::logFormat(HATLogger::LogLevel::ERROR, __FILE__, __LINE__, __VA_ARGS__)

等...和:

#define HATStreamFatal   HATLogger::logStream(HATLogger::LogLevel::FATAL, __FILE__, __LINE__)
#define HATStreamError   HATLogger::logStream(HATLogger::LogLevel::ERROR, __FILE__, __LINE__)

可以在下面调用这些宏:

HATFormatError("This is an %s message", "ERROR");
HATStreamError << "This is an " << "ERROR" << " message" << std::endl;

我想用相同的名字称呼他们:HATLogError。正确的宏将在寻找括号时在编译时确定。 到目前为止,我已经看到了一些示例,展示了如何通过参数的数量来区分宏,但没有任何东西可以处理“非-括号”大小写。

有人知道如何实现吗?

最简单的方法是根本不重载宏,而是让宏 return 成为同时重载 operator<<operator() 的对象。像这样:

class error_logger {
public:
    error_logger(
        HATLogger::LogLevel level,
        char const * file,
        char const * line
    ) : level{level}, file{file}, line{line} { }

    template <typename... T>
    void operator()(T && ... args) {
        HATLogger::logFormat(level, file, line, std::forward<T>(args)...);
    }

    template <typename T>
    HATLogger::logStream operator<<(T && arg) {
        HATLogger::logStream stream{level, file, line};

        stream << std::forward<T>(arg);

        return stream;
    }

private:
    HATLogger::LogLevel level;
    char const * file;
    char const * line;
};

(此示例假设 HATLogger::logStream 可以移动。可能需要根据您的代码的详细信息对此示例实现进行调整,但基本方法是我在这里演示的。)

现在你可以做:

#define HATFormatFatal  (error_logger{HATLogger::LogLevel::FATAL, __FILE__, __LINE__})

然后HATFormatFatal << ...HATFormatFatal(...)都可以用