【问题标题】:Use enum to determine type of return result ( a hack using Macro )使用枚举来确定返回结果的类型(使用宏的黑客攻击)
【发布时间】:2017-09-19 06:45:12
【问题描述】:

我有许多类型的游戏对象,它们在某些方面相互关联。
所有关系都由Map<K1,K2> 实现。

#include <vector>
using namespace std;

template<class K1,class K2> class Map{ //N:N relation
     public: std::vector<K2*> getK2(K1* k1){/* some code */return std::vector<K2*>();} 
     public: std::vector<K1*> getK1(K2* k2){/* some code */return std::vector<K1*>();}
     //... various function ...
};

这里是方便所有关系查询的集线器类GameRelation:-
(只是一个例子,不需要注意所有细节)

class Human{};   class House{};    class Dog{};
class GameRelation{
    public:
    #define RELATION(A,B,EnumName) Map<A,B> Map##EnumName;  \
    enum EnumName##Enum{EnumName};   \
    std::vector<B*> getAllRight(EnumName##Enum e,A* a){  \
        return Map##EnumName.getK2(a);  \
    }
    //... various function ...
    RELATION(Human,House,Own) 
    //I can insert any relation that I want
};

上面的宏扩展成类似的东西:-

Map<Human,House> MapOwn; 
enum OwnEnum{Own};   
std::vector<House*> getAllRight(OwnEnum e,Human* a){  
    return MapOwn.getK2(a);  
}

这是它的使用方法(full demo):-

int main() {
    GameRelation gameRelation;
    std::vector<House*> houses=gameRelation.getAllRight(GameRelation::Own,new Human()); 
    //get all "House" that is "Own" by a "Human" 
    return 0;
}

经过一些测试,它运行良好。每个人都对神奇的结果感到满意。

但是,我的意识告诉我,这是一个 hack。
对于内容辅助(例如智能感知)和自动重构来说,这也有点糟糕。
如果我想将他们的实现转移到.cpp,我还需要 awesome hacking X-MACRO

问题:

  • 有什么优雅的(不那么hack的)方法吗?这是什么?
    “否”可以是一个有效的答案。
  • 当我需要这种(奇怪的)功能时,X-MACRO 是(专业的)方法吗?

【问题讨论】:

  • using namespace std;?哦,来吧,你比那更好......
  • 看起来您正试图用命令式编程语言中的枚举和宏来重塑关系数据模型。您是否考虑过只使用 SQLite 之类的东西?您可能有一个表“house”、一个表“human”和一个表“house_ownership”,其中前两者的外键。
  • @Quentin 同意,这只是为了演示。这是“ideone”的默认设置。
  • @Christian Hackl 是的,我也感觉到了,但我从来不知道有这样的图书馆。谢谢。 SQLite 是否使用哈希函数?我讨厌哈希,它很慢。 (我已经分析了 std::unordered_map。)
  • @javaLover:我不知道 SQLite 是如何实际实现的,但是当您需要本地基于文件的关系数据库时,它是标准的行业解决方案。例如,Android、iOS、Firefox 和最新的 Visual Studio IDE 都使用它。但是,如果您需要完全在内存中的东西并且负担不起 I/O 操作,那么它可能是错误的选择。

标签: c++ enums macros c++14 x-macros


【解决方案1】:
struct GameRelation{
    template <typename A, typename B>
    struct Relation {
        std::vector<B*> getAllRight(A* a) {
            return map.getK2(a);
        }

    private:
        Map<A, B> map;
    };

    Relation<Human, House> own;
};

int main() {
    GameRelation gameRelation;
    std::vector<House*> houses = gameRelation.own.getAllRight(new Human()); 
}

【讨论】:

  • 我发现的唯一(次要)缺点是封装较少 - 我将直接访问“自己”字段。
  • @javaLover 为什么这是个问题? Relation 专门用作访问器,只要不提供它们,就可以禁止对其进行任何不需要的操作。
  • 这是一句智慧的话。
  • 请您告诉我这种技术叫什么?...创建一个专门包含单一/常见类型字段的类的技术...
  • @javaLover 我不知道它有什么通用名称。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多