C/C++
前言
代码中经常看到类是以下的宏定义,用于在程序启动时自动注册元数据信息映射:
宏名称和参数:
#define EMPLACE_METADATA_INFO_MAPPING(type, catagory, name, proxy_name) \
__attribute__(( \
constructor)) void RegisterMetaDataInfo##proxy_name##name() { \
getMetaDataInfoMapping()[type] = { \
catagory, #name, #proxy_name}; \
}
宏接受四个参数:
type:通常是一个类型标识符,作为映射的键。
catagory(应该是category的拼写错误):表示类别信息。
name:元数据的名称。
proxy_name:代理名称。
宏展开后的代码结构:
__attribute__((constructor)) void RegisterMetaDataInfo##proxy_name##name() {
getMetaDataInfoMapping()[type] = {
catagory, #name, #proxy_name
};
}
这个宏的作用是在程序启动时,自动调用一个注册函数,将指定类型type对应的元数据信息(类别、名称、代理名称)存入一个全局映射中,方便后续通过type快速查找对应的元数据。这样设计可以实现自动注册机制,减少手动调用注册函数的麻烦。
关键点说明:
attribute((constructor)):这是GCC和Clang编译器的一个函数属性,表示该函数会在main()函数执行之前自动调用,通常用于初始化工作。
RegisterMetaDataInfo##proxy_name##name:这是函数名,使用了宏拼接操作符##,将proxy_name和name拼接到函数名中,确保每个注册函数名称唯一,避免重名。
getMetaDataInfoMapping():这是一个函数,返回一个映射(比如std::map或std::unordered_map),用于存储元数据信息。
[type] = { catagory, #name, #proxy_name }:将一个结构体或类似的数据赋值给映射中type对应的元素。这里用到了#操作符,将宏参数name和proxy_name转换成字符串字面量。
测试
下面编写一个测试用例:
#include <iostream>
#include <string>
#include <unordered_map>
// 定义一个结构体来存储元数据信息
struct MetaDataInfo {
std::string category;
std::string name;
std::string proxy_name;
};
// 返回一个全局的映射,用于存储元数据
std::unordered_map<int, MetaDataInfo>& getMetaDataInfoMapping() {
static std::unordered_map<int, MetaDataInfo> mapping;
return mapping;
}
// 你的宏定义,修正了拼写错误 category
#define EMPLACE_METADATA_INFO_MAPPING(type, category, name, proxy_name) \
__attribute__((constructor)) void RegisterMetaDataInfo##proxy_name##name() { \
getMetaDataInfoMapping()[type] = { category, #name, #proxy_name }; \
}
// 使用宏注册几个元数据
EMPLACE_METADATA_INFO_MAPPING(1, "CategoryA", MyData, ProxyX)
EMPLACE_METADATA_INFO_MAPPING(2, "CategoryB", OtherData, ProxyY)
EMPLACE_METADATA_INFO_MAPPING(3, "CategoryC", MoreData, ProxyZ)
int main() {
auto& mapping = getMetaDataInfoMapping();
for (const auto& [key, info] : mapping) {
std::cout << "Type: " << key << "\n";
std::cout << " Category: " << info.category << "\n";
std::cout << " Name: " << info.name << "\n";
std::cout << " Proxy Name: " << info.proxy_name << "\n";
std::cout << "----------------------\n";
}
return 0;
}
说明:
定义了一个MetaDataInfo结构体,存储类别、名称和代理名称。
getMetaDataInfoMapping()返回一个静态的全局映射,存储type到MetaDataInfo的映射。
使用宏EMPLACE_METADATA_INFO_MAPPING注册了3条元数据,分别对应不同的type。
attribute((constructor))保证注册函数在main()之前自动执行,完成注册。
main()函数中遍历映射并打印所有注册的元数据信息。
你可以直接编译运行这段代码,看到自动注册的元数据被正确存储和访问。需要注意的是,这个宏和代码在GCC或Clang下支持__attribute__((constructor)),在其他编译器(如MSVC)可能需要其他方式实现自动初始化。
总结
这个宏的作用是在程序启动时,自动调用一个注册函数,将指定类型type对应的元数据信息(类别、名称、代理名称)存入一个全局映射中,方便后续通过type快速查找对应的元数据。这样设计可以实现自动注册机制,减少手动调用注册函数的麻烦。