代码之家  ›  专栏  ›  技术社区  ›  startresse

自定义type\u索引顺序,无boost

  •  0
  • startresse  · 技术社区  · 2 年前

    我有以下地图:

    std::map<std::type_index, std::set<Status *>> statuses;
    

    它存储 Status 好了,多亏了他们 std::type_index 。 但是,我想控制此贴图中对象的顺序(例如,我有两个类 Burn Stun 继承自 地位 ,我想 typeid(Stun) < typeif(Burn) 所以当我遍历地图时,我得到 std::set<Stun> std::set<Burn> )。

    我想实现一个自定义 type_index 类,但如果没有boost,我似乎找不到任何方法来实现这一点,boost是一个巨大的库,我不想将其包含到我的项目中。

    关于如何在地图中定制订单,有什么建议吗?

    1 回复  |  直到 2 年前
        1
  •  3
  •   463035818_is_not_an_ai    2 年前

    您可以将 type_index 使用比较器生成所需顺序的自定义类型。

    示例来自 cppreference 修改使用 std::map 而不是 std::unordered_map 使用自定义比较器:

    #include <iostream>
    #include <typeinfo>
    #include <typeindex>
    #include <map>
    #include <string>
    #include <memory>
     
    struct A {
        virtual ~A() {}
    };
     
    struct B : A {};
    struct C : A {};
    
    struct my_type_index {
        std::type_index index = std::type_index(typeid(void));
        my_type_index() = default;
        my_type_index(std::type_index i) : index(i) {}
        bool operator<(const my_type_index& other) const {
            static std::map< std::type_index,int> rank{
                { std::type_index(typeid(A)) , 1},
                { std::type_index(typeid(B)),  2},
                { std::type_index(typeid(double)),  3},
                { std::type_index(typeid(int)),  4},
                { std::type_index(typeid(C)),  5}
            };        
            return rank[index] < rank[other.index];
        }
    };
    
    
    int main()
    {
        std::map<my_type_index, std::string> type_names;
     
        type_names[std::type_index(typeid(int))] = "int";
        type_names[std::type_index(typeid(double))] = "double";
        type_names[std::type_index(typeid(A))] = "A";
        type_names[std::type_index(typeid(B))] = "B";
        type_names[std::type_index(typeid(C))] = "C";
       
        for (const auto& e : type_names) {
            std::cout << e.first.index.name() << " " << e.second << "\n";
        }
    }
    

    output :

    1A A
    1B B
    d double
    i int
    1C C
    

    Fran§ois Andrieux建议进行改进:

    struct my_type_index {
        std::type_index index = std::type_index(typeid(void));
        int rank = 0;
        my_type_index() = default;
        my_type_index(std::type_index i) : index(i) {
            auto it = ranks.find(i);
            if (it != ranks.end()) rank = it->second;
        }
        
        static const std::map<std::type_index,int> ranks;
        
        bool operator<(const my_type_index& other) const {        
            return rank < other.rank;
        }
    };
    
    const std::map<std::type_index,int> my_type_index::ranks = [](){
        std::map<std::type_index,int> result;
        std::type_index index_order[] = {
            std::type_index(typeid(A)),
            std::type_index(typeid(B)),
            std::type_index(typeid(double)),
            std::type_index(typeid(int)),
            std::type_index(typeid(C)) 
        };
        for (size_t i = 0; i < std::size(index_order);++i){ result[ index_order[i]] = i+1; }
        return result;
    }();
    

    排名存储在静态地图中 ranks 和每个实例 rank 已经在施工中进行了评估(而不是每次比较,即比较现在更便宜)。此外,映射现在是从一个更健壮的数组生成的(您不能再错误地键入索引/排名)。此外,地图是 const ,即 find 而不是 operator[] 用于查找。不在地图中的元素将被分配等级0。事实上,之前也是这样,但之前 操作员[] 可能会向地图中添加不必要的元素。