宏定义中的#与##运算符:字符串化和连接
请说明 C/C++ 宏中 #(字符串化)和 ##(标记连接)运算符的作用和用法,给出它们在日志系统、注册表、X-Macro 等场景中的实际应用示例。
回答
古法程序员
# 字符串化:将宏参数转为字符串字面量。
#define STR(x) #x
#define TO_STR(x) STR(x) // 确保参数先展开
int version = 42;
cout << STR(hello); // "hello"
cout << TO_STR(__LINE__); // "42"(先展开 __LINE__)
// 日志宏
#define LOG(msg) cout << __FILE__ ":" << TO_STR(__LINE__) << " " << msg << '\n';
## 标记连接:将两个标记拼接为一个新标记。
#define MAKE_TYPE(name) using name##Vector = std::vector<name>
MAKE_TYPE(int); // using intVector = std::vector<int>
MAKE_TYPE(string); // using stringVector = std::vector<string>
// 字段访问器
#define FIELD(name) \
decltype(auto) get_##name() { return name##_; } \
void set_##name(const auto& v) { name##_ = v; }
class Person {
int age_;
string name_;
public:
FIELD(age)
FIELD(name)
}; // 生成 get_age()/set_age()/get_name()/set_name()
X-Macro 中的 ## 应用:
#define ERROR_MAP \
X(OK, 0, "Success") \
X(NOT_FOUND, 1, "Not found")
enum class ErrorCode {
#define X(name, code, msg) name = code,
ERROR_MAP
#undef X
};
#define ERROR_TO_STRING_CASE(name, code, msg) \
case ErrorCode::name: return msg;
const char* to_string(ErrorCode e) {
switch(e) {
ERROR_MAP
#undef X
default: return "Unknown";
}
}
注意:## 生成的标记必须是合法的预处理标记。参数为 __VA_ARGS__ 时 ## 可用于去除多余逗号。