IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++高级宏操作 -> 正文阅读

[C++知识库]C++高级宏操作

最近在看一个c++各数据类型和 JSON 或 xml 互转的库,重点阅读了其中宏的编写

xpack项目链接

// 结构体格式如下
struct User{
    long uid;
    string name;
    XPACK(A(uid, "id"), O(name));	//用于指示各变量的特殊操作
}
#define XPACK(...)   \
    X_PACK_COMMON    \
    X_PACK_DECODE_BEGIN X_PACK_N(X_PACK_L1, X_PACK_L1_DECODE, __VA_ARGS__) }  \
    X_PACK_ENCODE_BEGIN X_PACK_N(X_PACK_L1, X_PACK_L1_ENCODE, __VA_ARGS__) }

结构体中的变量数目不定,采用可变参数宏:

...__VA_ARGS__配合使用,...处填充的内容将填充到___VA_ARGS__

__VA_ARGS__替换最后一个具体参数后所有内容包括逗号等

当然c++并不提倡使用可变参数

#define X_PACK_COMMON \
public:               \
    static bool const __x_pack_value = true;
#define X_PACK_DECODE_BEGIN                         \
    template<class __X_PACK_DOC, class __X_PACK_ME> \
    void __x_pack_decode(__X_PACK_DOC& __x_pack_obj, __X_PACK_ME &__x_pack_self, const xpack::Extend *__x_pack_extp) {(void)__x_pack_extp;

// encode function
#define X_PACK_ENCODE_BEGIN                          \
    template <class __X_PACK_DOC, class __X_PACK_ME> \
    void __x_pack_encode(__X_PACK_DOC& __x_pack_obj, const __X_PACK_ME &__x_pack_self, const xpack::Extend *__x_pack_extp) const {(void)__x_pack_extp;

从这里开始可以看出XPACK已经被展开成了一个静态常量和两个函数,x_PACK_N()被包在函数内部


#define X_PACK_N(LEVEL, ACTION, ...)  X_PACK_COUNT(LEVEL, ACTION, __VA_ARGS__, _99,_98,_97,_96,_95,_94,_93,_92,_91,_90,_89,_88,_87,_86,_85,_84,_83,_82,_81,_80,_79,_78,_77,_76,_75,_74,_73,_72,_71,_70,_69,_68,_67,_66,_65,_64,_63,_62,_61,_60,_59,_58,_57,_56,_55,_54,_53,_52,_51,_50,_49,_48,_47,_46,_45,_44,_43,_42,_41,_40,_39,_38,_37,_36,_35,_34,_33,_32,_31,_30,_29,_28,_27,_26,_25,_24,_23,_22,_21,_20,_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1) (ACTION, __VA_ARGS__)

#define X_PACK_COUNT(LEVEL, ACTION, _99,_98,_97,_96,_95,_94,_93,_92,_91,_90,_89,_88,_87,_86,_85,_84,_83,_82,_81,_80,_79,_78,_77,_76,_75,_74,_73,_72,_71,_70,_69,_68,_67,_66,_65,_64,_63,_62,_61,_60,_59,_58,_57,_56,_55,_54,_53,_52,_51,_50,_49,_48,_47,_46,_45,_44,_43,_42,_41,_40,_39,_38,_37,_36,_35,_34,_33,_32,_31,_30,_29,_28,_27,_26,_25,_24,_23,_22,_21,_20,_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1,N,...) LEVEL##N

很离谱第一次看到这种操作,算是奇技淫巧了,分析一下做了什么

举个例子:x_PACK_N(L,A, myA, myY)扩展成X_PACK_COUNT(L, A, myX, myY, 一坨)(ACTION, __VA_ARGS__)

X_PACK_COUNT(L, A, myX, myY, -99, 一坨, _3, _2, _1)

X_PACK_COUNT(L, A, _99, _98, 一坨, _2, _1, N)

N获取到_2

这个宏相当于是一个截取功能,理解成一个窗口

这一步的结果是X_PACK_L1_2(X_PACK_L1_DECODE, __VA_ARGS__)

注意:此方法适用于gcc,msvc中需要再添加一个宏#define EXPAND(...) __VA_ARGS__,并且包含在X_PACK_COUNT()之外

#define EXPEND(X_PACK_COUNT()) EXPEND(ACTION, __VA_ARGS__)

后面经过几步简单的变换转换成

X_PACK_L1_DECODE(A(uid, "id")) X_PACK_L1_DECODE(O(name))

再来看一下X_PACK_L1_DECODE

/// XPACK /
//=======DECODE
#define X_PACK_L1_DECODE(x)             { X_PACK_L1_DECODE_##x }
//----
#define X_PACK_L1_DECODE_X(FLAG, ...)   X_EXPAND_FLAG_##FLAG xpack::Extend __x_pack_ext(__x_pack_flag, NULL); X_PACK_N2(X_PACK_L2, X_PACK_DECODE_ACT_O, __VA_ARGS__)
#define X_PACK_L1_DECODE_E(FLAG, ...)   X_EXPAND_FLAG_##FLAG xpack::Extend __x_pack_ext(__x_pack_flag, NULL); X_PACK_N2(X_PACK_L2, X_PACK_DECODE_ACT_E, __VA_ARGS__)
#define X_PACK_L1_DECODE_B(FLAG, ...)   X_EXPAND_FLAG_##FLAG xpack::Extend __x_pack_ext(__x_pack_flag, NULL); X_PACK_N2(X_PACK_L2, X_PACK_DECODE_ACT_B, __VA_ARGS__)
#define X_PACK_L1_DECODE_AF(FLAG, ...)  X_EXPAND_FLAG_##FLAG X_PACK_N2(X_PACK_L2_2, X_PACK_DECODE_ACT_A, __VA_ARGS__) // extend define in ACTION

#define X_PACK_L1_DECODE_O(...)         X_PACK_L1_DECODE_X(F(0), __VA_ARGS__)
#define X_PACK_L1_DECODE_M(...)         X_PACK_L1_DECODE_X(F(M), __VA_ARGS__)
#define X_PACK_L1_DECODE_A(...)         X_PACK_L1_DECODE_AF(F(0), __VA_ARGS__)

#define X_PACK_L1_DECODE_I(...)         X_PACK_N2(X_PACK_L2, X_PACK_DECODE_ACT_I, __VA_ARGS__)
//=======ENCODE
#define X_PACK_L1_ENCODE(x) { X_PACK_L1_ENCODE_##x }
//-----
#define X_PACK_L1_ENCODE_X(FLAG, ...)   X_EXPAND_FLAG_##FLAG xpack::Extend __x_pack_ext(__x_pack_flag, NULL); X_PACK_N2(X_PACK_L2, X_PACK_ENCODE_ACT_O, __VA_ARGS__)
#define X_PACK_L1_ENCODE_E(FLAG, ...)   X_EXPAND_FLAG_##FLAG xpack::Extend __x_pack_ext(__x_pack_flag, NULL); X_PACK_N2(X_PACK_L2, X_PACK_ENCODE_ACT_E, __VA_ARGS__)
#define X_PACK_L1_ENCODE_B(FLAG, ...)   X_EXPAND_FLAG_##FLAG xpack::Extend __x_pack_ext(__x_pack_flag, NULL); X_PACK_N2(X_PACK_L2, X_PACK_ENCODE_ACT_B, __VA_ARGS__)
#define X_PACK_L1_ENCODE_AF(FLAG, ...)  X_EXPAND_FLAG_##FLAG X_PACK_N2(X_PACK_L2_2, X_PACK_ENCODE_ACT_A, __VA_ARGS__) // extend define in ACTION

#define X_PACK_L1_ENCODE_O(...)         X_PACK_L1_ENCODE_X(F(0), __VA_ARGS__)
#define X_PACK_L1_ENCODE_M(...)         X_PACK_L1_ENCODE_X(F(M), __VA_ARGS__)
#define X_PACK_L1_ENCODE_A(...)         X_PACK_L1_ENCODE_AF(F(0), __VA_ARGS__)
//-----
#define X_PACK_L1_ENCODE_I(...)         X_PACK_N2(X_PACK_L2, X_PACK_ENCODE_ACT_I, __VA_ARGS__)

很明显可以看出:用##来实现switch逻辑

X_PACK_L1_DECODE(A(uid, "id"))扩展成{X_PACK_L1_DECODE_A(uid, "id")}


后面的操作大同小异,经过几次扩展后从转为N2同时L1转为L2再转成X_PACK_ACT类型的宏,最后由如下的宏转换成最终代码

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ decode act ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define X_PACK_DECODE_ACT_O(M)                        \
        __x_pack_ext.vsize = sizeof(__x_pack_self.M); \
        __x_pack_obj.decode(#M, __x_pack_self.M, &__x_pack_ext);

// enum for not support c++11
#define X_PACK_DECODE_ACT_E(M)                        \
        __x_pack_ext.vsize = sizeof(__x_pack_self.M); \
        __x_pack_obj.decode(#M, *((int*)&__x_pack_self.M), &__x_pack_ext);


#define X_PACK_DECODE_ACT_A(M, NAME)                                      \
    {                                                                     \
        static xpack::Alias __x_pack_alias(#M, NAME);                     \
        xpack::Extend __x_pack_ext(__x_pack_flag, &__x_pack_alias);       \
        const char *__new_name = __x_pack_alias.Name(__x_pack_obj.Type());\
        __x_pack_ext.vsize = sizeof(__x_pack_self.M);                     \
        __x_pack_obj.decode(__new_name, __x_pack_self.M, &__x_pack_ext);  \
    }
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-29 12:49:03  更:2021-10-29 12:51:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 4:22:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码