重载 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(...)
都可以用
我目前正在开发一个 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(...)
都可以用