前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【“宏孩儿”入门】通过宏定义将类型和函数结构解耦

【“宏孩儿”入门】通过宏定义将类型和函数结构解耦

原创
作者头像
六月丶
发布2023-08-01 09:52:21
2190
发布2023-08-01 09:52:21
举报
文章被收录于专栏:六月-游戏开发

想象这样一个场景,我们有一个表结构体StudentInfo,同时用数组存储它作为一张表,我们需要提供一套根据Key来增删改查的函数操作这张表。

(这里可能有聪明的小伙伴会想到为什么不用哈希表来存储,这样不就自带一套根据Key来增删改查函数了吗?

是的一般情况下可以这样,但也有些情景下不能使用哈希表,比如UE中TSet不支持同步。)

但如果每有一张这样的表我们都要写一套增删改查函数未免太累了。

我们仔细观察增删改查函数时会发现,除了操作的表,key不同外,代码结构上是相同的,那怎么让表和函数结构解耦呢?

因为表可能是私有成员同时还需要用到表的key,所以用模板还不太好解决。

可以考虑用宏来做。

比如在某个模块中有多张表:

代码语言:c++
复制
struct StudentInfo{

    int Id;

    std::string Val1;

    float Val2;

};



struct Fish{

    //...

}

//...



class Module{

//...

private:

    //SaveGame

    std::vector<StudentInfo> StudentInfoTable;

    std::vector<FishInfo> FishInfoTable;

    //其他表...

public:

    //各表的增删改查函数...

}

比如我们想为所有表提供一个Has函数,可以写个宏:

(如果对##的作用不了解可以点击看这篇文章)

代码语言:c++
复制
#define DECLARE\_DATA\_TABLE\_HAS\_METHOD(DataArray, KeyType, KeyField) \

bool DataArray##HasKey(KeyType FindBy##KeyField){                     \

    bool IsHas = false;                                             \

    for(const auto &Row : DataArray){                                 \

        if(Row.KeyField == FindBy##KeyField){                         \

            IsHas = true;                                             \

            break;                                                     \

        }                                                             \

    }                                                                \

    return IsHas;                                                     \

}                                                                     \

(这里不讨论实现性能问题,那不是这篇文章的主题)

然后可以在需要定义has函数的模块中加上这个宏传入表和key信息就等于生成了一个该表的Has函数:

代码语言:c++
复制
DECLARE\_DATA\_TABLE\_CRUD\_METHOD(StudentInfoTable, StudentInfo, int, Id)

等价于

代码语言:c++
复制
bool StudentInfoTableHasKey(KeyType FindById){

    //...

}

接下来就可以举一反三写出生成其它函数的宏,同时我们还可以写个宏来专门负责打包这些宏:

代码语言:c++
复制
//生成数据表基础的增删改查方法

#define DECLARE\_DATA\_TABLE\_CRUD\_METHOD(DataArray, RowType, KeyType, KeyField) \

DECLARE\_DATA\_TABLE\_HAS\_METHOD(DataArray, KeyType, KeyField)\

DECLARE\_DATA\_TABLE\_FIND\_METHOD(DataArray, RowType, KeyType, KeyField)\

DECLARE\_DATA\_TABLE\_FIND\_OR\_ADD\_METHOD(DataArray, RowType, KeyType, KeyField)\

//...

这样我们为每张表写增删改查函数就只需要一条宏:

代码语言:c++
复制
DECLARE\_DATA\_TABLE\_CRUD\_METHOD(StudentInfoTable, StudentInfo, int, Id)

这个例子只是用来理解思路。

**完整样例代码**:

代码语言:c++
复制
#include<iostream>

#include<string>

#include<vector>



#define DECLARE\_DATA\_TABLE\_HAS\_METHOD(DataArray, KeyType, KeyField) \

bool DataArray##HasKey(KeyType FindBy##KeyField){                     \

    bool IsHas = false;                                             \

    for(const auto &Row : DataArray){                                 \

        if(Row.KeyField == FindBy##KeyField){                         \

            IsHas = true;                                             \

            break;                                                     \

        }                                                             \

    }                                                                \

    return IsHas;                                                     \

}                                                                     \



#define DECLARE\_DATA\_TABLE\_FIND\_METHOD(DataArray, RowType, KeyType, KeyField)\

RowType \*DataArray##FindRow(KeyType FindBy##KeyField){\

    RowType \*Ret = nullptr;\

    for(auto &Row : DataArray){\

        if(Row.KeyField == FindBy##KeyField){\

            Ret = &Row;\

            break;\

        }\

    }\

    return Ret;\

}\



//前置依赖:Find

#define DECLARE\_DATA\_TABLE\_FIND\_OR\_ADD\_METHOD(DataArray, RowType, KeyType, KeyField)  \

RowType &DataArray##FindOrAddRow(KeyType In##KeyField){\

    RowType \*FindRow = DataArray##FindRow(In##KeyField);\

    if(FindRow == nullptr){\

        RowType Row;\

        Row.KeyField = In##KeyField;\

        DataArray.push\_back(Row);\

        FindRow = &DataArray[DataArray.size()-1];\

    }\

    return \*FindRow;\

}\





//生成数据表基础的增删改查方法

#define DECLARE\_DATA\_TABLE\_CRUD\_METHOD(DataArray, RowType, KeyType, KeyField) \

DECLARE\_DATA\_TABLE\_HAS\_METHOD(DataArray, KeyType, KeyField)\

DECLARE\_DATA\_TABLE\_FIND\_METHOD(DataArray, RowType, KeyType, KeyField)\

DECLARE\_DATA\_TABLE\_FIND\_OR\_ADD\_METHOD(DataArray, RowType, KeyType, KeyField)\







struct StudentInfo{

    int Id;

    std::string Val1;

    float Val2;

};



class Module{

//...

private:

    //SaveGame

    std::vector<StudentInfo> StudentInfoTable;

public:

    

    DECLARE\_DATA\_TABLE\_CRUD\_METHOD(StudentInfoTable, StudentInfo, int, Id)

    /\*

    DECLARE\_DATA\_TABLE\_HAS\_METHOD(StudentInfoTable, int, Id);

    DECLARE\_DATA\_TABLE\_FIND\_METHOD(StudentInfoTable, StudentInfo, int, Id);

    DECLARE\_DATA\_TABLE\_FIND\_OR\_ADD\_METHOD(StudentInfoTable, StudentInfo, int, Id);

    \*/

};



int main(){

    Module NewModule;

    std::cout << NewModule.StudentInfoTableHasKey(5) << "\n";

    std::cout << NewModule.StudentInfoTableFindRow(5) << "\n";

    StudentInfo &FindStudentInfo = NewModule.StudentInfoTableFindOrAddRow(2001);

    FindStudentInfo.Val1 = "zsd";

    FindStudentInfo.Val2 = 1.5f;

    std::cout << NewModule.StudentInfoTableFindOrAddRow(2001).Val2 << "\n";

    

    return 0;

}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档